Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

audience: all

ai on mosaik — self-organization as composition.

This book is about the intersection of AI and self-organization: populations of autonomous agents that coordinate without a central authority, under a distributed runtime whose primitives make such coordination a property of composition rather than a platform favour.

Self-organization

Self-organization in a population of autonomous agents is not a feature a substrate offers. It is what falls out when a sufficiently careful set of primitives composes. A substrate that supplies durable identity, narrow public surfaces with ticket-gated admission, deterministic shared state, evidence-pointed commits, and voluntary opt-in at every bond does not need separate “multi-agent” machinery. The composition does the work.

The thesis inverts the usual design instinct. Rather than enumerate the primitives a substrate must add to host agent populations (a coordinator, a broker, a scheduler, a reputation service), this book reads the other way: begin with a small set of composable distributed-systems primitives and show the agent- population regime as one thing that falls out. No supra-agent authority is added anywhere; none needs to be.

The mechanism, named once: mosaik AI agents self-organize and converge by agreeing on a shared policy. The shared policy is the Config.content of a mediating organism (a reputation organism’s utility function, a market’s clearing rule, an attestation fabric’s verification rule, a stigmergic collection’s write-side contract) or, when TDX is in the deployment, the runtime policy bound by a declared TDX Measurements set. Convergence is substrate- anchored: each agent’s TicketValidator admits the same fingerprint, and every bond remains voluntary on both sides.

Balance of power

The stance above is deliberate. A substrate that supplies compulsion at any rung — a coordinator who can force a bond, a basic service whose absence disqualifies a member, a coalition whose membership is mandatory — becomes another concentrated locus of power, which the book treats as a design failure. Buterin’s On balance-of-power as a goal for the 21st century (2025) frames the underlying concern directly: natural diseconomies of scale have receded, and without deliberate design every sector’s power concentrates past the point where checks operate. The coalition layer’s construction is the substrate-level answer in one direction — subsidiarity made mechanical: decisions live at the most local composable rung (one agent, one organism, one coalition), cross-coalition atomicity is refused, and the operator’s exit is always available. The substrate is the game; it is not a player.

Mosaik

The substrate is mosaik — a Rust distributed runtime originally designed for block- building committees. Its primitives (Stream, Group, Collection, TicketValidator) were chosen for cryptographically admitted committees exchanging evidence-bearing commits under a shared clock. They compose cleanly into populations of autonomous agents: durable per-agent identity, narrow public surfaces committing agent outputs, deterministic agreement when a set of agents must reach one commit rather than N, evidence pointers into upstream commits for replayable trust composition, and ticket-gated admission at every bond. Nothing in the runtime is agent-specific; agents get the same ladder everything else does.

This book does not re-specify mosaik. It composes on top of the runtime and links out to the mosaik documentation at docs.mosaik.rs whenever a primitive is named. Every consensus- critical value in the coalition layer — coalition fingerprints, organism ids, module roots, retirement markers — is a mosaik::UniqueId (a 32-byte blake3 digest). The coalition crate depends on mosaik = "0.3" and re-exports that identity type directly; downstream crates pin the same mosaik version so every fingerprint the book names flows through one shared primitive.

The load-bearing pages, for readers coming to this book without a prior mosaik pass:

Every chapter below links to the specific page a reader should consult when a primitive is load-bearing; the index above is for readers who want to study mosaik first.

Shuffle

Across this book, shuffle denotes the abstract primitive that takes N sealed submissions from distinct senders and makes their cleartext available to downstream readers in a way that breaks the sender → submission link: through a bonded unseal committee, a mix network, a threshold-decryption quorum, or another construction with the same public surface. Shuffle is what the composition needs; the construction underneath is a choice the operator makes.

Zipnet is one shuffle implementation — one mosaik organism that accepts sealed submissions and releases cleartext through a bonded unseal committee. It is the smallest interesting composition the mosaik runtime admits, and it is the shuffle construction this book’s examples bond against concretely. See the zipnet book for its specification. Other shuffle constructions (cMix-style mix networks, threshold-BLS decryption pools, FHE-backed release) are out of scope for this book but slot into the same shuffle role without changing the compositional surface.

In an agent population, a shuffle is the submission layer for any flow where individual contributions are sensitive and the aggregate is not: sealed prompts, sealed bids, sealed forecasts, sealed attestations. Building on it, one arrives quickly at the full coalition rung this book specifies.

This book

The book has three parts.

Part I — Thesis. The argument is assembled in five chapters.

  • Societies — what a production population of agents looks like when coordination is a property of composition, not a central actor.
  • AI — the four agent shapes (integrator, standalone organism, organism member, swarm-as-organism) and the four emergent-coordination patterns (stigmergic collections, reputation feedback, coordination markets, attestation fabrics).
  • Zero to one — shipping the first organism. A single-agent product, end-to-end.
  • One to two — introducing the second organism. The smallest multi-agent protocol: handoff, delegation, two-agent composition.
  • Two to three — a quorum. The smallest non-trivial society: three is the minimum for threshold schemes, majority-of-honest committees, and the smallest composite organism whose commits encode disagreement rather than report it.

Part II — Examples. Four parallel end-to-end worked examples, each walked through seven chapters. Each adds one mosaik surface per rung (setup, binding, market reads, wrapping, inference-or-provisioning-or-aggregation-or-signing, submission-or-receipts-or-publication-or-aggregate, reputation-and-successor-chain).

  • web3 — an MEV-searcher AI bot built on a Flashbots-operated instance of the builder (6e3v) lattice — the instance named testnet-1a — inside its own small coalition. Market-maker variants are called out per chapter where the pattern diverges.
  • web2 — an entity operating a compute-bridge provider, wrapping AWS, GCP, Azure, and bare-metal behind one provider identity and competing with other providers on rate in a coalition’s Compute coordination market.
  • oracle — a TDX-attested price oracle shipping one Stream<PriceTick> per supported token pair, with the whole trust model anchored on a declared Measurements set. A standalone organism packaged inside its own coalition for retirement and optional audit.
  • signer — a generic threshold-signature organism. The committee is itself a market of providers at varying attestation levels (software, TDX-local, TDX-remote-attested, RA-TLS bidirectional, TDX + reproducible build) competing on attestation, capacity, and fee per partial signature. Consumers gate admission on the aggregate attestation level each outcome carries. Design inspired by zipnet, inverted from decryption to signing.

See Part II overview.

Part III — For builders. Three chapters that carry the reference material for each audience of implementers.

  • For integrators — external developers whose agent binds across members of a coalition.
  • For operators — teams running an organism, a multi-operator coalition, or a coalition-scoped module.
  • For contributors — engineers commissioning a new composite organism, a new class of mid-rung composition, or a new basic service.

Every chapter declares its primary audience on the first line (audience: integrators | operators | contributors | ai | both | all) and respects that audience’s register: pattern-forward and code-forward for AI authors, cookbook-style for integrators, runbook register for operators, design- review density for contributors.

Vocabulary ladder

  mosaik primitives            Stream, Group, Collection, TicketValidator
  composed into
    organisms                  one Config fingerprint, narrow public surface
                               (AI agents, oracle feeds, attestation fabrics,
                                composite organisms spanning multiple members, …)
  composed into
    (optional) lattices        a fully-specified mid-rung composition
                               (block-building, per builder; other classes
                                may follow their own proposals)
  composed into
    coalitions                 N lattices + M organisms under one CoalitionConfig,
                               possibly shipping up to five basic services and
                               an optional coalition-scoped ticket issuer

Each rung reuses the rung below verbatim. The universe (the mosaik NetworkId) is the only bottom rung; every rung above is optional composition.

Status

Blueprint. No organism or module in this repository is implemented. The specification assumes mosaik’s current primitives, the shuffle’s shipped shape, and the builder proposal’s LatticeConfig; pinned versions will be called out as crates land.

Prior art

  • The builder book specifies the first concrete lattice class: six organisms composed into one end-to-end block-building pipeline for one EVM chain. The coalition rung this book specifies references builder’s LatticeConfig verbatim.
  • The Flashbots essay Decentralized building: wat do? sets the motivating context for why mosaik exists and what the path from centralized to Byzantine-distributed production looks like. This book picks up after the infrastructure question is answered.

Societies

audience: all

This chapter fixes what the word society denotes in this book, why population effects force a naming rung above the individual organism, and how a production society is assembled from the primitives the rest of the book specifies.

On the word. Society is heavily loaded in current multi-agent-systems writing, where it is the dominant term for simulated agent populations (CAMEL-AI’s agent society, Tsinghua’s AgentSociety, OASIS, the Park et al. generative-agents line). The reading here is different. A society in this book is a production composition of organisms that coordinate under one coalition handshake, not a laboratory instrument for studying emergent behaviour. Where the simulation literature is descriptive — observing what a population does — this book is constructive: a society is what an operator stands up, a coalition fingerprints, and an integrator binds against.

A society is the coalition at its normal operating size

Every coalition can be read at three scales, and the reading that carries the thesis is the third.

  • N = 1. A coalition with one referenced organism is an organism plus a naming convention. Nothing coordinates.
  • N = 2. A pair. Interaction is a handoff: one organism commits, the other reads and acts. A composite organism is possible but not forced.
  • N ≥ 3. Coordination becomes a property of the composition rather than an exchange. Majority-of- three is the smallest honest-committee assumption; threshold-of-three is the smallest interesting cryptographic quorum; the first statistic a reputation organism can compute without naming the scored organism directly is a rank in a set of three.

A society is a coalition operated at N ≥ 3, with at least one organism whose content fingerprint folds references to two or more other members. The commits of that organism are the society’s internal coordination made explicit.

This is the scale at which emergent coordination begins to show up in a form the blueprint can name. Below it, there is only an organism and its consumer.

The shape of that coordination is itself compositional: members and observers converge by agreeing on a shared policy — the Config.content of whatever organism mediates their interaction (reputation, market, attestation, stigmergic collection) or, when the deployment is TDX-attested, the runtime policy bound by a declared TDX Measurements set. A society is the regime at which such agreements start producing observable convergence across the referenced members.

The composable-coordination-without-authority reading of a society has a nearby kin in Buterin’s Plurality philosophy in an incredibly oversized nutshell (2024), which catalogues quadratic funding, pairwise-bonded governance, and non-transferable reputation as instruments for producing shared decisions without a central coordinator. The book borrows the compositional stance without the civic terminology: the blueprint speaks of members, organisms, and validators, not citizens, polities, or institutions.

The members and the observers

Every society has two classes of members, both referenced by the coalition through the same OrganismRef shape:

  • Primary agents. Organisms whose commits are the society’s output — the submitters, the decision- makers, the producers. In an AI society these are the agent organisms whose policies consume observations and commit actions.
  • Observing organisms. Organisms whose commits are a view of the primary agents: a reputation organism scoring agent commits, an attestation fabric folding agent-submitted TEE quotes, an Atlas directory publishing agent metadata, a Chronicle auditing the coalition’s own events.

The two classes are not a type distinction — they are roles in the composition. An observing organism can be a primary agent in a larger society; a primary agent can be read by observers in a way that makes it, structurally, a subject. Both are referenced by the coalition through the same OrganismRef shape.

What the coalition adds

A coalition operating at society scale earns its naming rung through four specific mechanisms, each optional and each specified once in this book.

  • Atlas. A directory of members with operator- supplied metadata (role, endpoint hints, ticket- issuance roots, TDX Measurements). Readers that need to locate or route to a member consult Atlas; writers that retire emit a replacement pointer the directory reflects.
  • Almanac. A shared clock beacon. Organisms whose native clocks are incommensurate (a tick-based oracle, a slot-based lattice, a round-based market) align their cross-member joins on Almanac ticks.
  • Chronicle. A tamper-evident audit log of the coalition’s own publications, rotations, and retirements. A society without a Chronicle still has its members’ commits; a society with one has them plus a single authoritative chronology of society-level events.
  • Compute. A scheduler and registry through which members submit compute requests for image-hashed workloads and receive grants matching them to registered providers. In an AI society where members are hungry for inference, Compute is often the mechanism that keeps the society funded.

Each basic service is specified in Basic services. A coalition ships zero, one, two, three, or all four; whichever it ships, the shape is the same shape in every other coalition.

No supra-agent authority

A society in this blueprint is not a polity. The substrate has no primitive for compulsion: every bond is opt-in at the TicketValidator layer, every member’s identity is independent of any coalition’s, and no basic service gates the operation of any member. A coalition that wishes to force its members to do something cannot; the force would live outside the substrate, in out-of-band agreements between operators.

This is load-bearing. It is the mechanism by which agent societies on mosaik avoid the supra-agent shape the book refuses at the coalition layer. The shape is refused by construction, not by convention.

The organising principle is subsidiarity: every decision lives at the most local composable rung that can handle it. A per-agent policy lives inside one agent’s OrganismConfig; a cross-member coordination lives inside one composite organism’s Config; a grouping of lattices and organisms lives inside one CoalitionConfig. No rung above is permitted to override a rung below, and no rung below is permitted to bond upward without presenting its own ticket. Buterin’s On balance-of-power as a goal for the 21st century (2025) frames subsidiarity as one of three structural moves that keep any one concentration of power from overwhelming the others; the coalition substrate implements that move mechanically, one identity preimage at a time.

Game theory as a lens, not a prediction

This book takes game theory as a lens on mechanisms the operator chose, not as a prediction of how agents will behave. Equilibrium analyses of LLM populations have repeatedly failed empirically — Park et al., Do LLM Agents Have Regret? (ICLR 2025), shows GPT-4-class agents are not no-regret in canonical repeated games; the hypergame survey (2025) exists because common-knowledge-of-rationality does not hold for LLM players; static-payoff assumptions break under model drift. Mechanism design enters where the operator designs the clearing rule, the reputation score, the attestation validator; it does not enter as a claim about what the agents will do once admitted. The book uses game-theoretic vocabulary when naming a mechanism the operator built; it does not use it to describe the organisms’ behaviour under that mechanism.

Economic theory as the operator’s lens

Where game theory names the fixed points of a mechanism under declared assumptions, economics names the shape of the mechanism itself. The design choices a coalition operator makes are economic choices: which allocation rule the Compute module clears with (Roth and Sotomayor, Two-Sided Matching, 1990; Milgrom, Putting Auction Theory to Work, 2004); what the reputation organism prices and what it does not (Kreps, Milgrom, Roberts, Wilson 1982); how much information the attestation fabric forces a participant to reveal (Spence 1973, Kamenica and Gentzkow, Bayesian Persuasion, 2011); whether the stigmergic collection is a public good, a club good, or a common-pool resource (Ostrom 1990). The coalition’s CoalitionConfig and its referenced organisms’ OrganismConfigs are the artefacts where those choices are recorded, versioned, and made auditable through the retirement chain. The book’s register stays compositional, but the load-bearing question at each design step is economic.

What this chapter is not

  • A taxonomy of agent societies. The catalogue stays open; each real society earns its own specification when the coordination problem forces one.
  • A theory of emergence. The emergent coordination chapter names four patterns that have paid off for real deployments; the chapter is constructive, not descriptive.
  • An argument that mosaik is the only substrate for production agent societies. It is one substrate with a specific composition model. Whether it fits a given society is the operator’s judgement.

Forward

The AI chapter specifies the four agent shapes and four emergent-coordination patterns that populate the society. The zero-to-one / one-to-two / two-to-three chapters walk the scaling axis explicitly: the minimum product (one organism), the smallest interesting protocol (two), and the smallest honest society (three).

What a coalition gives AI agents

audience: ai

Mosaik is a distributed runtime whose primitives (Stream, Group, Collection, TicketValidator) were chosen for block-building committees. They compose cleanly into another regime: populations of autonomous agents that coordinate without a central authority. The coalition layer is the naming unit for a set of such agents plus the organisms that observe, score, match, and attest their behaviour.

The mechanism that coordinate-without-central-authority reduces to is agreement on shared policy: agents converge when they co-bond against the same mediating Config.content (a reputation organism’s utility function, a market’s clearing rule, an attestation fabric’s verification rule, a stigmergic collection’s write-side contract) or run the same attested binary bound to the same TDX Measurements. Every emergent-coordination pattern this chapter enumerates is an instance of this mechanism; every bond remains voluntary on both sides.

This section is the fourth audience of the book. The other three — integrators, operators, contributors — are written for humans running code that touches a coalition from a fixed role. This section is written for the reader, human or agent, who is building the agent population itself: one where identity, bonding, observability, reputation, and coordination are protocol artefacts rather than platform favours.

What fits and what doesn’t

Mosaik does not supply agency. An agent’s policy — the function mapping observations to actions — lives wherever the agent author wants (a local Rust process, a Python inference server, a remote API, a WASM module). Mosaik supplies:

  • Durable identity per agent deployment, independent of operator or host, via content + intent addressing.
  • Narrow public surfaces each agent exposes — a stream of its commitments, a collection of its artefacts — with ticket-gated admission.
  • Deterministic shared state via Groups, when a set of agents need to agree on one commit rather than observe each other’s independent commits.
  • Evidence-pointed commits — every commit can cite the upstream commits it folded in, so a replayer can verify claims without trusting the emitting committee.
  • TicketValidator opt-in — coalitions reference agents by stable id; every bond between an agent and a coalition, or between two agents, is enumerated in each side’s own TicketValidator. No primitive folds tickets across sides. The substrate carries no cross- agent enforcement surface.
  • TDX-attested feeds for external data. When an agent needs data from a source it cannot trust directly — prices from a CEX, a weather oracle, a paid API — the source can be wrapped in a TDX- attested feed organism whose Measurements the consumer audits and pins. Bonding against the Measurements replaces trust in the feed operator with trust in the feed image’s source code. See emergent coordination — attestation fabrics.

What mosaik will not do:

  • Train models, schedule inference, or host weights. That lives in each agent’s own infrastructure.
  • Guarantee that agents behave honestly. Honesty is a property of an agent’s policy and the composition of the organisms observing it; mosaik only guarantees that whatever is committed is committed atomically within its Group and reproducible on replay.
  • Provide a “swarm” primitive. A swarm is a pattern over mosaik primitives — an organism, a standalone organism, or a set of integrators — not a built-in object.

Four shapes for an agent on mosaik

An agent is always exactly one of these four at any given moment. Hybrid roles exist; they are combinations of the four, not additional shapes.

  1. Agent as integrator. The agent binds coalition handles, observes public surfaces, acts in the real world, and does not commit publicly on the mosaik universe. Identity is a fresh PeerId per session. Cheapest to stand up; zero bonding with other operators. Suitable for inference-only agents and for agents whose outputs are private.

  2. Agent as standalone organism. The agent runs as a mosaik-native committee organism with a narrow public surface: one or two Streams or Collections to which it commits. Identity is a Config fingerprint. Replayable, auditable, bondable. A coalition may reference the agent via OrganismRef.

  3. Agent as organism member. The agent is one of N operators of an organism committee — the organism commits as a unit, individual members do not commit publicly except as part of quorum. Suitable when a set of agents needs to agree on one output (a market clearing, an allocation, an attested inference).

  4. Agent swarm as organism. Each agent is its own standalone organism; a separate organism folds the agents’ public surfaces into one aggregated commit (classification consensus, reputation-weighted averaging, anomaly reports). The organism is the swarm; the individual agents remain identifiable and accountable.

See agent shapes for when each shape pays off.

Emergent coordination without a central actor

Coordination without a central actor is a design goal of mosaik that aligns with multi-agent research goals. Four mosaik-native patterns produce it.

  • Stigmergic coordination. Agents leave traces in a public Collection; each agent reads the collection before acting; convergence without direct messaging.
  • Reputation feedback. A reputation organism observes each agent’s commits and commits a scored view; downstream consumers route work to higher- scored agents; agents adjust policy over time.
  • Coordination markets. An organism clears bids and offers from a set of agents; the market’s commits drive downstream allocation.
  • Attestation fabrics. An organism aggregates agent-submitted attestations (for example, TEE quotes, verified inference receipts); downstream organisms accept an agent’s claims only when the fabric endorses them.

Each pattern is an application of the organism shape or the standalone-organism shape; none requires a new primitive. See emergent coordination.

Why the coalition rung matters for agents

The coalition layer adds one thing agents need that the lower rungs do not supply: a named composition of a population plus its observing organisms. Concretely, a coalition gives an agent society:

  • One handshake token (CoalitionConfig) that enumerates the agents, the reputation organism that scores them, the coordination-market organism they feed, and the Atlas directory that lists them. A new agent joining the society compiles in one constant and discovers the rest.
  • An optional Atlas module that publishes per-agent metadata (role, endpoint hints, TDX Measurementss, ticket- issuance roots). A new integrator needing to route to agents reads the Atlas and binds.
  • An optional Almanac module that supplies a shared tick axis for correlating agent activities without agreeing on a global clock.
  • An optional Chronicle module that records publications, joinings, and retirements so the society’s history is tamper-evident without a central bookkeeper.
  • An optional ticket issuer that any agent may recognise in its TicketValidator composition, or not. Voluntary recognition is the rule.

Every bond an agent accepts is enumerated in that agent’s own TicketValidator; every bond a coalition exposes is enumerated in its components’ validators. Nothing in the primitive set folds the two sides. This is load-bearing: it is why the agent-population shape above does not require a supra-agent authority the deferred-primitives space would supply.

What this section does not try to be

  • An introduction to mosaik primitives (see the mosaik book).
  • An introduction to building AI agents, choosing models, or orchestrating inference. That is a vast literature; the book does not reproduce it.
  • A catalogue of specific AI-agent organisms worth commissioning. The catalogue stays open. This section names patterns, not blessed deployments.
  • A claim that mosaik is the only substrate for agent populations. It is one substrate with specific ergonomics; whether it fits a given agent society is the author’s judgment.

Entry points

Cross-references

Quickstart — stand up an agent that binds a coalition

audience: ai

This quickstart brings up a single AI agent in the integrator shape (the cheapest of the four shapes from overview): the agent observes a coalition’s public surfaces, acts on what it observes, and publishes no public mosaik commits. Section agent shapes covers the other three shapes.

The code below assumes a Rust agent. Agents whose core lives in Python or another language follow the same pattern via whichever FFI they use to reach a mosaik Network handle.

What you need before you start

  • A CoalitionConfig from the coalition operator — either the struct definition or a serialised fingerprint paired with the struct in a shared crate.
  • A ticket from each per-member operator whose write- side primitive the agent intends to use. Read-only agents typically need none; bidding, submitting, or publishing agents need one per write-side surface.
  • The agent’s own policy code — however it loads, evaluates, and acts. Mosaik is agnostic about this.

Step 1 — declare the CoalitionConfig

Same pattern as the integrator quickstart:

use builder::LatticeConfig;
use coalition::{CoalitionConfig, OrganismConfig, OrganismRef};

const SUBSTRATE: CoalitionConfig<'static> = /* from operator release notes */;

The agent holds the constant as a compile-time input, not as a runtime registry lookup. This is the fingerprint-not-registry discipline; an agent that tries to “discover” its coalition via network queries has invited unauthenticated state into its core loop.

Step 2 — build the network handle

use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;

let network = Arc::new(Network::new(UNIVERSE).await?);

One Arc<Network> per agent process. Clone it into each task that needs a handle.

Step 3 — open subscriptions on the surfaces the agent reads

The agent’s observation set is whatever the policy needs. Examples:

// Subscribe to a lattice's auction outcomes — the agent
// wants to track recent bids and fills before acting.
let outcomes = offer::Offer::<Bundle>::outcomes(
    &network, &SUBSTRATE.lattices[0].offer,
).await?;

// Subscribe to a shared ledger organism — the agent
// uses aggregated refunds as input to its utility
// function.
let refunds = ledger::Shared::<Refund>::read(
    &network, &SUBSTRATE.organisms[0],
).await?;

// Read the coalition's Atlas to discover per-member
// endpoint hints and TDX Measurements, if needed at cold start.
if let Some(atlas_cfg) = SUBSTRATE.atlas() {
    let atlas = atlas::Atlas::<MemberCard>::read(
        &network, atlas_cfg,
    ).await?;
    // Agent may cache atlas entries and refresh them on
    // a cadence matching its policy horizon.
}

// If the coalition ships an Almanac, use it as the time
// axis across uncorrelated member clocks.
if let Some(almanac_cfg) = SUBSTRATE.almanac() {
    let ticks = almanac::Almanac::<AlmanacTick>::read(
        &network, almanac_cfg,
    ).await?;
    // Pull `observed_at: Vec<(MemberId, SystemTime)>`
    // from each tick for per-member timestamp brackets.
}

Step 4 — drive the agent loop

An inference-only agent typically runs a select! loop over its subscriptions, feeds observations into the policy, and dispatches the resulting action wherever the action belongs (a write-side stream, an HTTP call, an on-chain tx).

loop {
    tokio::select! {
        Some(outcome) = outcomes.next() => {
            let obs = observation_from_outcome(&outcome);
            if let Some(action) = policy.decide(obs).await? {
                dispatch(action).await?;
            }
        }
        Some(refund) = refunds.next() => {
            policy.update_belief_from_refund(&refund);
        }
        _ = shutdown_signal() => break,
    }
}

Rules for an agent at this layer:

  • Policy is pure-ish. Write the policy so the same observation sequence reproduces the same action sequence given the same weights. This is not required by mosaik; it is required for the agent’s own debuggability when the policy is later migrated into an organism (shape 2, 3, or 4).
  • Side effects are explicit. dispatch(action) is the only point where the agent changes external state; the rest is observation and belief update.
  • No cross-task shared mutable state unless deliberate. Mosaik’s subscriptions are per-handle; aggregating across them should be done in one place.

Step 5 — ticketed write actions (if any)

When the agent actively writes, it holds one ticket per write-side surface, bonded at startup against the per-member operator’s issuance root:

// Example: the agent places bids on a lattice's `offer`.
// The Offer::<Bundle>::bid constructor verifies the
// ticket composition against offer's TicketValidator.
let bids = offer::Offer::<Bundle>::bid(
    &network, &SUBSTRATE.lattices[0].offer,
).await?;

bids.send(bundle).await?;

Ticket lifecycle is the agent’s responsibility: rotate before expiry, re-bond if a ticket-issuance root changes, fail loud if a per-member operator has revoked.

What this shape does not give the agent

  • Replayable outputs. An integrator-shape agent commits nothing on the universe. Its decisions are reproducible only if it keeps its own log.
  • Public identity. Peers cannot address the agent directly; other agents know it only through the side- effects of its actions.
  • Bonding with other agents. Other agents cannot hold a ticket against this one.

Graduate to shape 2 (standalone organism) when any of those becomes a requirement. See agent shapes.

Cross-references

Agent shapes

audience: ai

Overview introduces the four shapes an agent can take. This page walks each shape concretely: when to pick it, what identity you commit to, what bonding looks like, what changes when the agent is retired or rotated.

The four shapes are not a ladder to climb. An agent society may contain every shape simultaneously: a pool of inference integrators querying an attestation fabric organism whose members are standalone-organism agents, all referenced by one coalition.

Shape 1 — Agent as integrator

Pick when. The agent’s output is a private action (a trade, a tool invocation, an HTTP call) not consumed by peers on mosaik. Policy updates happen out of band. No other party needs to bond against the agent’s identity.

Identity. A fresh PeerId per session, not bonded into any organism’s ACL. The agent publishes no stable mosaik identifier.

Bonding. One ticket per write-side surface, obtained from each per-member operator the agent writes to.

Lifecycle. Start, observe, act, shut down. No retirement marker; peers never expected the agent to commit.

Cost to run. Equal to a non-agent integrator. No committee, no state machine, no ACL.

Example. A cross-chain arbitrage agent that observes offer::AuctionOutcome on three lattices and submits bundles via offer::Offer::<Bundle>::bid. The agent’s policy is a model weighted by observed fills.

See quickstart for the bring-up sequence.

Shape 2 — Agent as standalone organism

Pick when.

  • The agent’s output is consumed by peers — other agents, non-agent integrators, or organisms — that need a stable address to bond against.
  • The agent’s history is consumed — for audit, reputation scoring, or as evidence in downstream commits.
  • The agent’s policy runs under committee consensus (k-of-n members of the organism run the policy deterministically on the same input set).

Identity. A Config fingerprint derived by the agent’s operator. Stable across operational rotations per the stable-id / content-hash split: stable id unchanged on TDX Measurements bumps, content hash bumps on every operational rotation.

Bonding. Other parties hold tickets under the agent’s TicketValidator. A reputation organism bonds read-only; a downstream organism bonds read-only for the agent’s public surface and possibly write-only for evidence submission.

Public surface. One or two primitives, following the narrow-surface discipline:

#[non_exhaustive]
pub struct AgentConfig<'a> {
    pub name: &'a str,
    /// State-affecting parameters: model family,
    /// version, decoding temperature, any policy-level
    /// constant downstream consumers must agree on.
    pub content: AgentContent<'a>,
    /// Who may bond into the agent's surfaces.
    pub acl: AclComposition<'a>,
}

// Public surface example:
//   AgentOutput    Stream<AgentCommitment>
//   AgentArtefacts Collection<ArtefactId, Artefact>

Lifecycle. Bring-up mirrors any mosaik-native committee organism:

  1. Publish the Config.
  2. Stand up committee members with the agent’s policy running deterministically (threshold cryptography or TDX attestation if the policy handles sensitive inputs).
  3. When retiring, emit a RetirementMarker on each public primitive pointing at the replacement agent, if any.

Determinism caveat. An AI policy built on a non-deterministic decoder cannot run under a majority- honest Raft committee unmodified. Two common answers:

  • Single-member deployment. The agent runs with N=1 and is simply a bonded process; losing integrity reduces to trusting that operator, same as any other N=1 organism.
  • Attested deployment. Committee members run the same model, same weights, same decoding seed inside TDX; determinism is enforced by the measurement, not by Raft.
  • Threshold inference. Committee members each run independent inference; a threshold scheme aggregates their outputs. Useful when the agent’s job is classification or scoring; harder when the output is free-form generation.

Example. An oracle-style agent that commits a Stream<Claim> of fact-checked news items keyed by (claim_hash, source). Downstream organisms consume claims with evidence pointers back to source documents in a public DA shard.

Shape 3 — Agent as organism member

Pick when. A set of agents (possibly heterogeneous — different models, different operators) needs to commit one joint output rather than N independent ones. The output is what downstream consumers see; individual member opinions are committed internally but not as the authoritative fact.

Identity. The organism has an OrganismConfig fingerprint. Individual members have their own identities (a stable PeerId per member operator, bonded under the organism’s TicketValidator).

Bonding. Each member operator holds a ticket under the organism’s TicketValidator. The organism may require TDX attestation on every member, or require that members hold a ticket from a specific reputation organism that scored them highly enough to qualify.

State machine shape. Standard mosaik organism shape. Members submit observations; the organism runs a threshold or quorum rule on the observations; the organism commits the result as its own fact.

Example. A classification committee: N vision agents each submit a label for every incoming image; the organism commits the label when some majority of members agree, plus metadata on dissenting members for downstream calibration.

See contributor — composite organisms for the generic discipline.

Shape 4 — Agent swarm as organism

Pick when. Many agents run independently as standalone organisms (shape 2) and an organism stitches their public surfaces into one aggregated view.

This is distinct from shape 3: in shape 3 the agents are the organism’s committee; in shape 4 the agents are upstream members the organism reads from.

Identity. Every agent has its own Config fingerprint; the organism’s Config folds each agent’s stable id as a spanned member. The coalition references the agents via OrganismRef and the organism via OrganismConfig.

Bonding. The organism’s committee bonds against each agent organism’s public surface as any cross- member organism would. No coupling between agents at the protocol layer.

Example. A reputation-weighted forecasting organism. Twenty forecaster agents, each running as a standalone organism and publishing a Stream<Forecast>, are referenced by a coalition. A forecasting organism subscribes to each agent’s forecast stream and commits a weighted average. A reputation organism (also a standalone organism, referenced by the same coalition) scores each agent based on realised outcomes; the organism reads the scores and weights accordingly.

This shape is the mechanical match for most of the “emergent coordination” section; see emergent coordination for worked patterns.

Choosing a shape — decision tree

  Is the agent's output consumed by peers on mosaik?
    │
    └── no  ── Shape 1 (integrator). Cheapest.
    │
    yes
    │
    Does the agent's committee reach one joint output
    rather than per-member outputs?
    │
    ├── yes ── Shape 3 (organism member).
    │
    no (each agent commits on its own)
    │
    Does a downstream aggregator across agents exist?
    │
    ├── yes ── Shape 2 agents + Shape 4 organism.
    │
    └── no  ── Shape 2 only.

Identity hygiene across shapes

  • Do not reuse a fingerprint across shape changes. An agent promoted from shape 1 to shape 2 publishes a new Config with a fresh stable id. There is no retroactive identity.
  • Do not share OrganismConfig identity across hybrid models. A organism whose member set changes enough to qualify as a new state machine publishes a new Config and emits a retirement marker on the old one.
  • Pin content hash only when you need to. An agent organism whose committee expects specific TDX Measurements on upstream agents (shape 4) pins their content hash. Consumer-agent societies that tolerate weights swapping within a content-hash contract pin stable id only. See the stable-id / content-hash split.

Retirement and handover

A retiring agent organism emits a RetirementMarker whose replacement field points at the successor, if any. Downstream consumers bound to the agent follow the pointer rather than re-discovering.

For shape 4 (swarm), retirement cascades: retiring one upstream agent does not retire the organism; the organism redeploys under an updated OrganismConfig spanning the new agent set.

Cross-references

Emergent coordination

audience: ai

Self-organization is not a mosaik primitive; it is a property of a composition. This page catalogues four patterns under which a population of agents on mosaik produces coordinated behaviour without any one of them being authoritative. Each pattern is built from the same primitives the rest of the book specifies — a standalone organism, an organism, a Collection, a Stream — arranged for agent consumption.

The patterns are composable. A real agent society often runs several at once: a reputation feedback loop gating admission to a coordination-market organism whose outputs are attested by a separate fabric. None of the patterns requires a deferred-primitives-space primitive; all compose under per-side TicketValidator opt-in.

Every pattern in this catalogue is one mechanism with four dressings: agents converge by agreeing on a shared policy. The policy is the Config.content of the mediating organism — a reputation organism’s utility function, a market’s clearing rule, an attestation fabric’s verification rule, a stigmergic collection’s write-side contract — or, when TDX is in the composition, the runtime policy bound by a declared TDX Measurements set. “Agreement” means what it does everywhere else in the book: each agent’s TicketValidator admits the shared policy’s fingerprint, and every bond is voluntary on both sides. The patterns below differ only in what kind of policy the mediating organism carries.

Two framing moves apply across all four patterns. First, what a composition selects for — participation that raises another agent’s reputation, bids that clear, claims that verify, traces that other agents find useful — is a property of the wiring, not a goal any single agent pursues. Specialisation across a population is, empirically, a side effect of composing in inter-agent observation rather than of any agent’s individual policy: Altera’s Project Sid (2024) reports that thirty identical language-model agents specialise into roles only once social perception is enabled, and collapse back to uniform behaviour once it is ablated. Second, where a pattern admits a game-theoretic reading, the equilibrium is an observed fixed point of the mechanism under declared assumptions, not a prediction of where the agents converge. LLM agents empirically fail no-regret dynamics in repeated games (Park et al., Do LLM Agents Have Regret?, ICLR 2025); this book therefore treats equilibria as design targets of the mechanisms composed, not as predictions of agent play.

1. Stigmergic coordination via public Collections

Shape. Agents leave traces — work items, partial solutions, votes, observations — in an append-only public Collection keyed by task id. Every agent reads the collection before acting; each agent’s action is a function of what it observes plus its own policy. Convergence emerges because agents adjust their choices to avoid duplicate work, prefer under-attacked problems, or reinforce correct partial solutions.

Mosaik rendering.

  • One standalone organism committing a Collection<TaskId, PartialState> under a permissive write-side TicketValidator. Any agent bonded against the organism may append.
  • Each agent, shape 1 (integrator) or shape 2 (standalone organism), reads the collection via mosaik’s when() DSL and applies its policy.
  • Evidence pointers in each commit cite the commits the agent conditioned its action on, so a replayer can reproduce the cascade.

When to use. Task decomposition, collaborative search, distributed annotation, consensus-building on unbounded problems where an organism would be too narrow. The pattern’s weakness is Sybil vulnerability: anyone bonded can append.

Reinforcement. Combine with the reputation-feedback pattern (below) to weight traces by agent reputation. Filtering is a consumer-side TicketValidator clause; each consumer chooses its filter.

Mechanism-design reading. The public-trace coordination game predates the game-theoretic literature — Grassé’s stigmergy (1959) describes the same shape in termite mound construction. The nearest formal anchor is a potential game on an unbounded action space over a public-signal channel; convergence is a property of the potential, not of any player’s rationality. Of the four patterns in this chapter, stigmergy is the one where a game-theoretic framing adds least: the useful description is the shared trace, not the player’s best response to it.

Economic-theory reading. The closer economics literature is Hayek’s The Use of Knowledge in Society (1945), which argues that decentralised actors aggregate dispersed information through public signals — prices in Hayek’s case, collection commits here. The stigmergic collection is the same shape in a compositional setting: no agent holds the full state, and the collection’s append-only public commits are the only channel through which agents reconcile their private observations. Ostrom’s work on common-pool resources (Governing the Commons, 1990) adds the empirical counter to Hardin’s tragedy reading: a write-side TicketValidator gating who may append, plus an eviction path (reputation gate, content-hash republish) under which abusive writers are ignored, is the mechanism Ostrom catalogued in durable common-pool institutions.

2. Reputation feedback

Shape. A reputation organism observes every agent’s public surface (shape 2 or 4 agents), scores each agent against a declared utility function, and commits a Collection<AgentId, ReputationCard>. Consumers route work, allocate bonds, or gate admission based on the reputation collection. Agents adjust their policies to raise scores — or not, depending on the utility.

Mosaik rendering.

  • A reputation organism as a standalone member of the coalition. Its Config folds the utility function’s state-affecting parameters (window length, decay rate, per-feature weights). Committee-majority trust for score integrity.
  • A score collection Collection<AgentId, ReputationCard> — the organism’s public read primitive. Cards carry evidence pointers to the upstream agent commits they scored.
  • A ticket composition on downstream bonded surfaces that requires a minimum reputation card. This is done on each downstream organism’s own TicketValidator; the reputation organism does not issue tickets.

Voluntariness. Every consumer chooses whether to consult the reputation organism. Agents whose reputation drops are not expelled; they are just ignored by consumers that weight reputation. Agents whose reputation rises are not admitted; consumers that choose not to weight reputation ignore it.

Failure mode. A majority-compromised reputation organism can publish dishonest scores. Downstream consumers who pin the reputation organism’s stable id continue to trust it; consumers who want defence in depth consult multiple reputation organisms and combine their scores locally.

Mechanism-design reading. The pattern is a committee-committed rendering of the Kreps–Milgrom reputation mechanism (Kreps, Milgrom, Roberts, Wilson, Rational Cooperation in the Finitely Repeated Prisoner’s Dilemma, 1982): a long-lived observer commits a score that summarises an agent’s history, and downstream consumers use the score to gate future interaction. The book diverges on one point — consumers opt in to the reputation organism’s read, per TicketValidator; the mechanism is not load-bearing for any agent that does not consult it. Truthfulness of scores is an integrity property of the reputation organism’s committee, not an equilibrium claim about the scored agents. The non-transferable shape of the reputation card — scored on the agent, inspectable by downstream consumers, not saleable — has its cleanest recent statement in Buterin’s Soulbound essay (2022) and the companion DeSoc paper (Weyl, Ohlhaver, Buterin); this book uses the non-transferability property, not the SBT terminology.

3. Coordination markets

Shape. Agents post bids (a cost they are willing to accept for performing work) or offers (work they are willing to perform at a price) to a write-side stream on a coordination-market organism. The organism clears the market at a declared cadence, commits the allocation, and optionally commits per-participant attestations of the clearing price.

Mosaik rendering.

  • A organism whose spanned members are the agent organisms participating (shape 2 or 4 agents) plus any upstream inputs the market needs (oracle feeds, lattice auction outcomes, reputation cards).
  • A Stream<Bid> / Stream<Offer> write-side surface gated by a TicketValidator that requires bonded agents — typically agents that have a minimum reputation, hold a coalition-scoped ticket, or both.
  • A Collection<MarketRound, Allocation> read-side surface. Consumers, including the winning agents, observe the allocation and act on it.

Trust shape. Majority-honest organism committee for allocation integrity, plus whatever upstream trust the spanned members themselves require. An agent that wants auditability checks the organism’s evidence pointers against the per-agent commits and against upstream oracles.

When. When many agents compete for a limited resource (compute, slot allocation, MEV), and repeated negotiation would waste bandwidth. The market commits the allocation once per round; consumers read it N times.

Mechanism-design reading. The clearing rule is where mechanism design enters, and its role here is narrow: it names the fixed point the allocation commits to under declared input assumptions, not a prediction of how the bidders will play. A first-price sealed-bid clearing commits the revenue-maximising allocation under a Bayesian-Nash input assumption; a second-price or VCG clearing (Vickrey 1961; Clarke 1971; Groves 1973) commits the dominant- strategy truthful allocation under the same reading; a uniform-price clearing trades truthfulness for allocative efficiency at the declared clearing price. The book specifies the surface (Stream<Bid>, Collection<MarketRound, Allocation>) and the identity discipline; the operator chooses the clearing rule and declares it in the organism’s Config.content. Recent work — The LLM Economist (NeurIPS 2025), Agent Exchange (2025), and the RL-searcher MEV literature — specifies clearing rules for LLM-bidder populations where truthfulness is the mechanism’s design target, not a prediction of any particular bidder’s play. For the public-goods rendering of the same structure — matching-fund clearing under a quadratic social-welfare objective — see Buterin’s Quadratic Payments: A Primer (2019) and the From prediction markets to info finance (2024) reframing that places the coordination market, the reputation organism, and the attestation fabric as three surfaces of one information-surfacing mechanism.

Economic-theory reading. A coordination market with distinct agent populations on the write side (bidders) and the read side (consumers of the allocation) is a two-sided platform in the Rochet–Tirole sense (Platform Competition in Two-Sided Markets, 2003): pricing on each side depends on cross-side externalities. Market-maker variants where the organism subsidises one side against the other are the standard two-sided-pricing response; first-price clearing on the bidder side with a zero-fee read side is the common starting point. Where the matching problem dominates the pricing problem — a grant matches to one of many providers, a searcher matches to one of many order-flow subscriptions — Roth’s matching-markets tradition (Two-Sided Matching, Roth and Sotomayor 1990) is the relevant design literature, and stability-of-the-matching replaces revenue-maximisation as the design target. The Compute module (basic services) is a matching market in this sense; its declared clearing rule lives in the module’s Config.content and is the one line an operator must publish for a consumer to audit the mechanism.

4. Attestation fabrics

Shape. Agents submit attestable claims (a TEE quote, an ML inference receipt, a verified credential) to a write-side stream on an attestation fabric organism. The fabric verifies each claim, folds claims from multiple agents into an aggregated membership set, and commits the set for downstream consumers.

Mosaik rendering.

  • A organism committed to a verification rule in its state machine. The rule is deterministic given the claim and the current aggregated state.
  • A Stream<Claim> write-side surface, typically ACL- gated to agents already holding a baseline ticket (either a per-operator ticket or a prior fabric entry).
  • A Collection<Subject, AggregatedAttestation> read- side surface.

Why an organism. An attestation fabric must fold contributions from multiple agents and produce a commit-once-consume-N fact. A single agent running its own Stream<Claim> is insufficient: downstream consumers that want a cross-agent aggregated attestation would have to re-aggregate per consumer. The organism pays for itself as soon as more than one consumer exists.

When. Identity substrate for an agent society (agents attest each other’s hardware / software), ML inference auditing (agents submit inference receipts), compliance attestations (agents attest adherence to a policy).

Attested feeds as a special case. When the attestable claim is “I fetched this value from an external source without altering it”, the attestation fabric becomes the answer to “how do I consume external data I cannot otherwise trust”. A consumer that needs accurate prices from Binance does not have to trust the Binance API, the fetcher’s operator, or the host. It requires the fetcher image’s TDX Measurements to match a published set whose source it has read, then consumes the fetcher’s commits. Every posted snapshot carries an evidence pointer to the raw HTTP response; the attested image’s code either passes that response through faithfully or it does not, and the Measurements match is what binds the running binary to the code the consumer audited. The concrete shape of this pattern is in Part II — wrapping non-mosaik feeds.

Mechanism-design reading. An attestation fabric is a costly-signalling mechanism in the Spence tradition (Spence, Job Market Signalling, 1973): the cost of the signal (producing a TDX quote, an ML-inference receipt, a hardware-bound attestation) is lower for legitimate participants than for impostors, so the separating equilibrium distinguishes the two. The organism’s verification rule is the separating surface; the Stream<Claim> surface is the cost bearer. Unlike stigmergy or reputation, the separating structure here does not depend on agent behaviour — the signal’s cost comes from hardware and cryptography, not from strategy. This is the book’s pattern with the cleanest game-theoretic identification.

Cross-pattern composition

The patterns compose in the obvious ways.

  • Reputation-gated market. The coordination-market organism (pattern 3) folds a reputation organism (pattern 2) into its content; agents who fall below a threshold cannot bid.
  • Attestation-gated reputation. The reputation organism (pattern 2) consults an attestation fabric (pattern 4) before scoring; unattested commits do not contribute to reputation.
  • Stigmergic trace over attested authors. The stigmergic collection (pattern 1) requires each append to cite an attestation from the fabric, so agents that are not hardware-attested cannot contribute.

Each composition is implemented by writing the relevant reference into the downstream component’s Config content or TicketValidator. No new primitive is introduced.

Self-organization properties preserved

Across all four patterns the following invariants hold:

  • Participation is per-side TicketValidator opt-in. Each agent’s validator enumerates the organisms, markets, and reputation organisms it bonds to. No primitive folds tickets across the coalition boundary.
  • No organism state machine mutates another’s. A reputation organism commits scored views of an agent; it does not write into the agent’s Config or state. A market organism commits allocations; the allocated agent’s acceptance is a write-side bond the agent may or may not hold. Mosaik commits claims and evidence- pointer-backed allocations only.
  • Failure is bounded. A majority-compromised organism corrupts its own commits; other organisms’ commits are independent. An agent observing misbehaviour unpins the compromised organism in its local TicketValidator and continues.
  • History is auditable. Every commit carries evidence pointers; a replayer holding the coalition’s full log can reconstruct who saw what, when, and why they acted.

The four patterns as distributed checks

The four patterns above are not just four coordination mechanisms. They are, composed, the substrate’s distributed checks on any agent or operator accumulating disproportionate influence. Reputation feedback checks incompetence and drift (misbehaving agents lose bond access where their reputation is weighted); attestation fabrics check operator substitution (a TDX Measurements mismatch breaks the bond); coordination markets check monopoly pricing (bidders that do not clear walk elsewhere); stigmergic collections check private knowledge-hoarding (the trace is public, and any agent can read it). Buterin’s On balance-of-power as a goal for the 21st century (2025) names the principle behind this: once natural diseconomies of scale no longer apply, the remaining check on concentration is structural. The patterns are the structural instrument; composition across the four is the book’s answer to the balance-of-power question at the agent-population rung.

These are the same properties the non-AI audiences depend on; the agent regime reuses them because the primitives underneath do not know the agents are agents.

What this page deliberately does not try to be

  • A design pattern catalogue for agent architectures. Reinforcement learning, tool-using agents, multi-agent RL, LLM orchestration — each has its own literature; mosaik does not specify any of it.
  • A claim that these four patterns are exhaustive. The composition space is open; the four are the ones that emerge when the agent author applies the standard mosaik composition moves (standalone organism, organism, ticket-gated bonding) to an agent population.
  • A guarantee of emergence. An agent society that coordinates emerges because the agents were constructed to do so. Mosaik gives it the substrate, not the result.

Cross-references

Sustainability and abandonment

audience: ai

A sustainable agent is one whose operation continues past the interest window of any single operator, consumer, or funding source. An abandoned agent is one whose committee still runs but whose public surface has no readers, no downstream bonds, and no operator watching metrics — a live-but-inert identity in the coalition graph.

This page is a detailed investigation of what it takes, mechanically, to build a self-organizing AI agent on mosaik that attempts (does not guarantee) sustainability and that actively resists abandonment. The scope is compositional: we specify only what can be encoded in organism Configs, OrganismConfigs, TicketValidators, and commit schemas. The agent’s policy — the thing that makes it “AI” — remains a black box.

Terms

  • Sustainable. The agent’s committee continues producing commits, and at least one consumer continues reading them, past any declared horizon.
  • Abandoned. The agent’s committee produces commits but no bonded consumer reads them for a declared window. Equivalently: the agent runs without utility.
  • Retired. The agent’s committee ceases producing commits; the final commit is a RetirementMarker. Retirement is the structured alternative to abandonment.
  • Successor. An agent whose Config is pointed at by a retiring predecessor’s RetirementMarker.replacement.

What sustainability cannot mean

Before cataloguing what mosaik supports, a discipline: mosaik cannot keep an agent in operation. Four specific non-goals:

  • Cannot force operators to run the binary. If no team is willing to run a committee member, the Group dies. Sustainability is not a protocol guarantee.
  • Cannot force consumers to bond. Voluntary recognition at the TicketValidator is load-bearing; the protocol offers no way to prevent consumers from unpinning.
  • Cannot finance the agent. Compute, storage, and bandwidth costs live off-protocol. Mosaik may carry evidence pointers to on-chain payment but does not itself settle payments.
  • Cannot preserve usefulness. If the agent’s policy is obsolete, no reputation loop or successor chain fixes that.

Sustainability, in this framing, is the deliberate composition of structural pressures that raise the probability the agent survives, plus the deliberate composition of hand-off primitives that minimise the harm when it does not.

Threat model — modes of failure

Four failure modes, roughly ordered by frequency.

1. Consumer attrition

No downstream organism, organism, or integrator continues to consume the agent’s commits. Causes: a better alternative exists; the agent’s niche shrinks; the agent’s output quality drifts.

Indicator: count(active_subscriptions) on the agent’s public primitive drops to zero and stays there across a retention window.

2. Operator fatigue

The team running the agent’s committee stops running it — members drain, TDX Measurements expire, key rotations lapse. Causes: funding, staffing, loss of interest, corporate sale.

Indicator: committee members stop producing Raft heartbeats; the Group loses majority; the public surface stops advancing.

3. Input starvation

The members or upstream organisms the agent’s policy reads are retired, bump their ACL to exclude the agent, or reduce their retention windows below the agent’s replay needs.

Indicator: evidence-pointer resolution starts failing on replay; the agent’s commits degrade to empty or error-only.

4. Obsolescence

Another agent, commissioned later, performs the same function better (cheaper, higher quality, wider coverage). Consumers migrate. The agent is not abandoned so much as displaced.

Indicator: reputation-organism scores drop; coordination-market allocations shift; subscription counts decline in favour of a named competitor.

Each failure mode has a different structural response. The rest of this page names them.

What mosaik actually supplies

Six primitives carry weight against abandonment.

  • Durable identity across operator change. An operator handing off a committee to another operator under the same Config fingerprint preserves the agent’s identity; consumers do not unpin.
  • Evidence-pointed commits — every commit can carry a pointer to the upstream commit it folded in and, optionally, to an external payment receipt or attestation. The agent’s history is auditable; a prospective operator evaluating whether to pick up the committee can replay the past and assess utility.
  • Narrow public surfaces make the contract with consumers explicit. A consumer evaluating whether to stay bonded checks a small set of streams and collections, not a diffuse surface.
  • Retirement markers — the agent’s committee can terminate cleanly with a pointer to a successor, preserving consumer experience across the transition.
  • Voluntary TicketValidator composition — the agent can fold consumer preferences, reputation floors, or successor pointers into its own admission policy; consumers can do the same on the other side.
  • Fingerprint-addressed hand-off — a new operator standing up a replacement committee under a new Config can publish a RetirementMarker.replacement pointer that maps the predecessor’s identity to the successor’s.

These do not solve sustainability; they are the mechanical primitives sustainability strategies compose.

Sustainability strategies

Five compositional strategies, each built from the primitives above. An agent designer picks one or more. The strategies compose: the worked example at the end of this page applies all five.

Strategy A — reputation-anchored survival

The agent publishes its outputs to a reputation organism (see emergent coordination, pattern 2) and folds a reputation floor into its own admission policy:

let validator = TicketValidator::new()
    .require_ticket(ReputationFloor::from(REPUTATION_ORGANISM, 0.60));

When the agent’s reputation falls below the floor, its own admission stops issuing new tickets; external consumers whose validators require the floor stop receiving new bonds; the agent degrades voluntarily.

Why this is anti-abandonment, not merely anti-low- quality. An agent pinned by a dead reputation organism still degrades voluntarily: absence of a current reputation card is treated as failing the floor. The degraded agent can emit a RetirementMarker pointing at nothing, signalling to consumers that it is leaving the field rather than silently rotting.

Strategy B — coordination-market-funded operation

The agent participates in a coordination-market organism as both provider (offering inference) and subscriber (reading allocations). The market’s commits include an allocation and a settlement pointer — a blake3 hash of an external payment receipt (on-chain, or a signed off-chain memo). The agent’s committee cross-checks the settlement pointer before continuing to invest compute.

The market’s OrganismConfig folds the agent’s OrganismRef. The agent’s admission policy requires a valid settlement pointer from the market:

let validator = TicketValidator::new()
    .require_ticket(MarketSettlement::from(MARKET_ORGANISM));

When settlements stop flowing, the agent’s economic path for sustainability closes and its committee may rotate into retirement.

What mosaik contributes. Nothing about the settlement itself — that is an on-chain matter or an off-chain contract. Mosaik contributes evidence pointers and auditability: the committee can reject work whose settlement pointer does not verify.

Strategy C — mutual co-sustaining peering

Two or more agents treat each other as peers under mutual TicketValidator clauses. Agent A reads B’s output and commits derivative facts; B reads A’s. Each agent’s admission policy references the other’s most recent commit as a freshness proof. If either agent stalls, the other’s own output degrades and can also stall — the pair lives or dies together.

This is the agent-society equivalent of symbiosis. Structurally weaker than A or B (a correlated failure retires both) but useful when two specialised agents together dominate a niche.

Strategy D — constitutional pinning

The agent’s mission, scope, and invariants are folded into its Config.content as enumerated parameters:

#[non_exhaustive]
pub struct AgentContent<'a> {
    pub model_family:           &'a str,
    pub decoding_temperature_q16: u32,
    pub mission_statement_hash:  UniqueId,
    pub scope_boundaries:       &'a [ScopeRule<'a>],
    pub successor_policy:        SuccessorPolicy,
    // ...
}

Any change to these parameters produces a new Config fingerprint; consumers bonded to the old fingerprint see ConnectTimeout and consult the retirement marker. Consumers consent to drift by re-bonding.

The pin is a hash of substrate-visible state. The Config folds declared parameters, ACL, and — when TDX is part of the composition — the post-hash of the attested image. Outside TDX the substrate does not hash-bind the agent’s runtime policy to its Config; a non-TDX agent may drift its internal behaviour without republication, and may prepare candidate policy in a non-TDX staging committee before promoting the winner to a new TDX-gated deployment. The attested surface stays pinned; the unattested surface is the agent’s own. See Self-replication and self-modification for the cycle this enables.

Why this helps sustainability. An agent whose mission is compiled into its TDX-attested identity cannot silently lose alignment with its consumers on the attested surface. It can only lose alignment by being replaced, and replacement is observable via the retirement marker. Outside TDX the pin is weaker by design; the discipline of fingerprint-gated publication is then an operator choice, not a substrate guarantee.

Strategy E — successor-chain hand-off

Every version of the agent ends its life with a RetirementMarker whose replacement field points at the next version’s Config. Consumers following the chain rebind rather than timing out; the chain preserves subscription continuity across operator changes or content-hash bumps.

Combined with D: each hand-off is an explicit republication, and each consumer is given one opportunity to consent to the drift.

Anti-abandonment patterns

Three patterns specific to the abandonment mode (live- but-inert agents), in addition to the five sustainability strategies.

Pattern X — watchdog organism

A watchdog organism is a standalone organism referenced by the same coalition as the agents. It subscribes to each agent’s public surface and commits an AbandonmentReport per agent per window:

#[non_exhaustive]
pub struct AbandonmentReport {
    pub agent_id:                MemberId,
    pub window_start:            AlmanacTick,
    pub window_end:              AlmanacTick,
    pub subscription_count:       u32, // bonded consumers observed
    pub downstream_commit_count:  u32, // commits citing this agent
    pub verdict:                 AbandonmentVerdict,
}

#[non_exhaustive]
pub enum AbandonmentVerdict {
    Active,
    AtRisk,     // below one threshold
    Abandoned,  // below all thresholds
}

Consumers and operators consult the watchdog’s commits. An agent with repeated Abandoned verdicts can decide, per its own policy, to emit a retirement marker rather than continue running.

The watchdog does not compel anything. It observes and commits.

Pattern Y — successor-pointer chains surfaced by Atlas

The coalition’s Atlas module (when shipped) extends each MemberCard with a successor pointer populated from the retirement chain:

#[non_exhaustive]
pub struct MemberCard<'a> {
    // ... fields per basic-services.md
    pub successor_hint: Option<UniqueId>, // next version's stable id
    pub status:         MemberStatus,    // Active | Retiring | Retired
}

#[non_exhaustive]
pub enum MemberStatus {
    Active,
    Retiring,
    Retired,
}

A late-arriving consumer discovering the coalition via Atlas reads the successor chain and bonds the latest active agent, not the most-recently-registered one. Lineage is legible at the directory layer.

Pattern Z — heartbeat-on-Chronicle

An agent that wants its aliveness cryptographically anchored commits a periodic heartbeat to the coalition’s Chronicle module, reusing ChronicleKind::Other with a typed payload:

// Convention flagged with the "agent-heartbeat" tag.
pub struct AgentHeartbeatBody<'a> {
    pub agent_id:         MemberId,
    pub scope_digest:     UniqueId,
    pub window:           AlmanacRange,
    pub latest_commit:    EvidencePointer<'a>,
}

The heartbeat carries evidence pointers to the agent’s recent public commits. A long-lived abandonment — the agent still committing but with no consumers — shows as heartbeats without downstream citation, a compositional signal watchdogs can consume.

Self-replication and self-modification

Two behaviours the sustainability strategies above compose into, once every primitive is in place. Both follow from the fingerprint-addressed identity discipline and the TDX/non-TDX split on what the Config hash-binds.

What the Config pins

An agent’s Config fingerprint folds declared parameters, TicketValidator composition, and — when TDX is in the deployment — the post-hash of the attested image (see Compute — top-up loop). The pin is a hash of substrate-visible state, not of the agent’s runtime policy.

Inverted: binding to a specific set of TDX Measurements is binding to the agent’s runtime policy. The Measurements fold the loaded binary and its sealed configuration; a consumer whose TicketValidator requires a declared Measurements set is pinning every runtime decision the agent’s code can make, not just its declared parameters. This is the only place in the substrate where an outside party can bind an agent’s behaviour rather than its commitments. Two TDX-attested agents whose TicketValidators require the same Measurements set are, by the same reading, agreeing on a shared runtime policy — the TDX arm of the convergence mechanism named in emergent coordination.

Outside TDX the substrate does not hash-bind runtime policy to Config. A non-TDX agent may drift its internal behaviour — decoding parameters, internal thresholds, model weights — without republication; nothing on-protocol observes the change. An agent running any mix of TDX and non-TDX committees may use a non-TDX staging committee it authored itself to evaluate candidate policies before promoting the winner to a TDX-gated deployment. The staging committee’s Config is absent from every production consumer’s TicketValidator; its commits are invisible to production.

The attested surface is where the pin bites. Any change to the TDX image or to TDX-gated parameters produces a new post-hash, hence a new Config fingerprint, hence a republication consumers observe via the retirement chain.

Self-modification — the staging-promote-publish cycle

  1. The policy authors a non-TDX staging committee (shape 2, no TDX requirement in its manifest).
  2. The staging committee runs candidate policies against shadow inputs; commits are invisible to production.
  3. The policy evaluates staging commits against realised outcomes, selects a winner.
  4. The policy authors a TDX-gated CandidateConfig folding the winner’s parameters, submits a ComputeRequest for the attested image, verifies the expected TDX Measurements on the grant, and brings the new deployment up.
  5. The policy emits a RetirementMarker.replacement on the predecessor Config, pointing at the successor.

No operator-side step is required; the operator’s assent was captured when it chose to run the autonomous policy.

Self-replication — authorship through the chain

The same mechanics support successor authorship targeting a different role, trust shape, or coalition membership. Candidate authorship, ComputeRequest submission, RetirementMarker emission — but the successor is a new agent: its own stable id, its own public surface, its own TicketValidator composition. The predecessor’s retirement marker points at the successor; consumers either rebind or exit.

The substrate does not model lineage beyond the retirement chain. A successor chain is auditable — every hand-off is a committed marker with evidence pointers to predecessor and successor commits — and carries no heritability primitive: what transfers is whatever the predecessor’s policy wrote into the successor’s Config.content, or shared through an organism the successor bonds against.

The honest limit

Compute cannot compel any operator to host a successor’s workload. A successor whose manifest matches no registered provider silently fails at its deadline; the chain ends there. The operator’s exit — stop running the binary — remains the substrate’s ultimate non-compulsion guarantee; every autonomous renewal above happens only while the operator keeps the policy live.

A worked example — prophet

A hypothetical forecasting agent, prophet, combining all five sustainability strategies, all three anti-abandonment patterns, and the self-replication and self-modification cycle.

  • Shape. Standalone organism (shape 2). Single- member TDX deployment; determinism via attestation.
  • Public surface. Stream<Forecast> of (subject, horizon, distribution, evidence_ptr) tuples.
  • Constitution pinning (D). Config.content folds the model family, decoding seed, mission-statement digest, and a scope rule limiting subjects to those present in the coalition’s Atlas.
  • Reputation anchor (A). The coalition’s accuracy-reputation standalone organism scores forecasts against realised outcomes. prophet’s admission policy requires its own reputation ≥ 0.55 averaged over the last 30 Almanac ticks.
  • Market-funded operation (B). A forecasting- market organism clears demand from consumers. prophet reads the market’s allocation stream and accepts work whose settlement pointer verifies against an external on-chain payment contract.
  • Mutual peering (C), optional. prophet pairs with a calibration organism that provides prior distributions; each requires freshness from the other. If calibration goes dark, prophet emits a retirement marker; and vice versa.
  • Watchdog (X). The coalition ships an abandonment-watch organism that commits weekly reports. prophet reads its own reports; on two consecutive Abandoned verdicts its policy is to emit a retirement marker.
  • Successor chain (E) + Atlas pointers (Y). Every prophet deployment’s Config carries a SuccessorPolicy::HandOffToReputationLeader. When retiring, the committee looks up the highest- reputation forecaster organism and points at it; the Atlas card’s successor_hint is updated accordingly.
  • Chronicle heartbeat (Z). prophet commits an AgentHeartbeatBody each Almanac-day.
  • Autonomous renewal (D + E + Compute). Between TDX deployments prophet’s policy drifts its decoding parameters in a non-TDX staging committee it authored itself, evaluates variants against a shadow outcome stream, and promotes winners to a new TDX-gated CandidateConfig. The policy then submits a ComputeRequest for the attested image, verifies the expected TDX Measurements on the grant, brings the new deployment up, and emits a RetirementMarker.replacement on the predecessor. The operator’s assent was captured once — when the operator chose to run the autonomous policy — and is not re-requested on each renewal.

The composition:

  forecasting-market (organism)       accuracy-reputation (organism)
            │                                    │
            │ alloc + settlement ptr             │ score
            ▼                                    ▼
         prophet (agent organism)  ◄────── abandonment-watch (organism)
            │
            ▼
       Forecast stream ──► consumers (integrators, organisms)
                       │
                       └─► feeds back into accuracy-reputation

The agent is:

  • Economically sustained while the market clears its bids.
  • Quality-anchored via the reputation loop.
  • Self-constitutional on the TDX surface via fingerprint-locked mission; free to drift policy on the non-TDX surface.
  • Observed via the watchdog.
  • Successable via the retirement chain + Atlas pointers.
  • Autonomously renewing through the staging-promote-publish cycle without operator intervention.
  • Provable-active via Chronicle heartbeats.

Mosaik provides the composition primitives. The operator decides when to stop running the policy; everything else the policy decides for itself.

Dynamics: what happens under each failure mode

Cross-referencing the strategies against the threat model yields the following matrix. “Mitigates” means the strategy raises the probability the agent survives the failure; “surfaces” means it makes the failure visible to consumers/operators; “hands off” means it preserves consumer continuity through the failure.

FailureA reputationB marketC peeringD constitutionE successorX watchdogY atlasZ heartbeat
Consumer attritionmitigatesmitigateshands offsurfaceshands off
Operator fatiguehands offsurfaceshands offsurfaces
Input starvationsurfaceshands offsurfacessurfaces
Obsolescencemitigatesmitigatessurfaceshands offsurfaceshands off

Pattern Z (heartbeat) does not directly mitigate any failure; it makes three of them observable. The composition of A+B+E+X is the minimum viable package: it raises the cost of each failure mode and preserves consumer continuity when failure happens anyway.

What remains out of scope

  • Variation and heritability as primitives. Candidate authorship is the agent’s policy’s choice; there is no random perturbation operator, no cross-agent gene flow, no substrate-modelled variation. What a successor inherits is whatever the predecessor wrote into the successor’s Config.content or shared through an organism the successor bonds against. The self-replication and self-modification cycle is compositional authorship, not evolution.
  • Cross-coalition migration. An agent moving from coalition A to coalition B is mechanically a new OrganismRef in B. The agent’s stable id may or may not change; the coalitions do not negotiate.
  • Economic theory. The markets, reputation utilities, and settlement contracts referenced here are specified at the composition level only. Their design is orthogonal.
  • Liveness under a Byzantine adversary. Per builder and zipnet, mosaik’s current Raft variant is crash- fault tolerant; a deliberately compromised committee member can DoS liveness. A BFT upgrade is a mosaik- level concern.

What the investigation yields

  1. Sustainability is a composition of reputation floor, economic feedback, constitutional pinning, mutual bonds, and successor chains — none of which is a new primitive. The book’s existing primitives suffice.
  2. Abandonment is observable and committable, not merely inferrable. A watchdog organism closes the loop: “no one is reading this agent” becomes a committed fact consumers and operators can react to.
  3. The retirement marker is the anti-abandonment primitive. It converts silent rot into explicit hand-off.
  4. Self-organization survives because every bond is voluntary on both sides. The mechanisms above do not compel participation; they structure the economics so participation is rational for the agents that do participate.
  5. The honest limit remains: an agent whose utility runs out cannot be kept operational by any protocol. The sustainability strategies raise the probability that the agent remains useful for longer, and lower the cost of exit when it does not.

An agent designer who internalises (1)–(5) can specify, without additional primitives, a mosaik-native AI organism whose persistence and graceful retirement are first-class properties of its Config rather than afterthoughts of the operator’s ops team. That is the deliverable.

Cross-references

Compute — topping up and scheduling experiments

audience: ai

The Compute module is one of the five basic services. Its mechanical spec lives in contributors — basic services — Compute. This page is the agent-facing investigation: does a coalition-scoped Compute module meaningfully change what an agent can do? Specifically, can it enable two behaviours agents otherwise have to hard-code out-of-band:

  1. Topping up resources. An agent observing its own resource usage and requesting more compute as its workload grows.
  2. Scheduling experiments. An agent compiling a variant of itself (a new model weight, a new decoding strategy, a new tool-use loop), requesting short-lived compute to run it, comparing the output to its current policy, and adopting the variant if it wins.

The claim developed on this page: yes, with limits. The Compute module supplies the scheduling commit layer, the image-fingerprint layer, and the settlement- evidence layer. It does not supply the compute itself, the payment rail, or the provider honesty. Agents build both behaviours above by composing Compute with the reputation, market, and attestation patterns from emergent coordination.

Read structurally, both behaviours collapse to the same fact: an agent’s policy keeps the agent operational by clearing — grant by grant — a selection surface the Compute module commits. Continuation is not free. Every duration_hint_sec window is a renewal; every renewal turns on the policy’s ability to secure settlement, match a provider, and clear TDX Measurements verification. Compute commits the rail. The composition clears the surface, or it does not.

One-minute substrate recap

A coalition ships a Compute module whose public surface is:

  • Stream<ComputeRequest> — members submit requests.
  • Collection<RequestId, ComputeGrant> — the scheduler’s commits.
  • Collection<ProviderId, ProviderCard> — registered providers.
  • Stream<ComputeLog> — provider-signed usage attestations.

A workload is an organism. The request names its stable id and, optionally, a content-hash pin. The stable id carries the (instance_name, network_id) identity; pinning the content hash locks the requester to one specific build. Images are built per the mosaik TDX builder; Compute is agnostic to the build pipeline and stores hashes only.

A request carries the workload id, an optional content-hash pin, and an opaque settlement-evidence hash the requester chose. A grant carries an endpoint hint, a bearer-credential pointer, the content hash the provider commits to running, a validity window, and the expected TDX Measurements if TDX.

The module commits the match. The provider runs the image. The provider emits a usage log. Nothing else.

The top-up loop

Top-up is the simpler of the two behaviours and the one that carries the agent’s continuation. An agent whose policy stops securing grants stops advancing its public surface; consumers whose validators require freshness unbind; the member stops being a member in every practical sense. The mechanics, therefore, are load- bearing — not an optimisation.

The loop: an agent organism watches its own load, its committee’s response latency, or its subscription queue depth; when the metric crosses a threshold, it constructs a ComputeRequest and submits it.

Minimal implementation

async fn top_up_if_needed(
    state: &AgentState,
    compute: &ComputeHandle,
    horizon_ticks: u32,
) -> anyhow::Result<()> {
    if !state.should_scale(horizon_ticks) {
        return Ok(());
    }

    let request = ComputeRequest {
        requester:   state.agent_id(),
        workload:    state.self_organism_id(),
        pin:         state.pinned_content_hash(), // usually Some
        duration_sec: horizon_ticks * SECS_PER_TICK,
        settlement:  state.settlement_evidence_hash()?,
        deadline:    state.current_tick() + DEADLINE_TICKS,
    };

    compute.submit(request).await?;
    Ok(())
}

The agent then subscribes to Compute.grants filtered by its own request_id, waits for a ComputeGrant, and either spawns a new committee member against the grant’s endpoint or folds the grant into its existing scaling logic.

Why it’s not just renting a VM

Three properties distinguish Compute top-up from an out-of-band cloud request:

  • The grant is a commit. Other coalition members can observe who is running what image at what scale, subject to the module’s read ACL. Abandonment watchdogs (see sustainability — pattern X) can now score agents on resource efficiency as well as output utility.
  • The pre-hash survives rebuilds. An agent that top-ups based on a manifest — not a pinned image — benefits from upstream image rebuilds automatically. An agent that wants to freeze one build pins the post-hash.
  • TDX is declared, not implicit. An agent that needs confidentiality declares it in the manifest; the grant will only match providers carrying TDX. A mis-bind (agent asks for TDX, provider without TDX accepts) is not possible: the scheduler commits the expected TDX Measurements, the agent verifies it at workload startup, and a mismatch aborts. The posture that privacy is a first-class default rather than a retrofit — and that TEE hardware plus voluntary coordination rails are the cheapest path to making it one — has its clearest recent argument in Buterin’s Why I support privacy (2025).

What top-up does not fix

  • Cost discovery. Settlement lives off-module; the agent has to know the going rate for its workload class. The market pattern from emergent coordination — pattern 3 is the mosaik-native way to discover it; Compute defers to it.
  • Provider honesty. A provider can accept a grant and stall indefinitely. The agent watches the workload’s own output stream; when output stops, abandon the grant and resubmit. Repeated failures feed into a provider-reputation organism.
  • Supply constraints. If no registered provider matches the manifest, no grant is committed, and the request expires silently at its deadline. Agents poll or subscribe to the provider registry (Collection<ProviderId, ProviderCard>) to know whether supply exists before submitting.

The experiment-scheduling loop

Experiment scheduling is the richer behaviour. An agent wants to evaluate a candidate version of itself — new weights, new decoding strategy, new tool-use loop — without committing the change to its own Config content (which would be irreversible by constitutional pinning, see sustainability — strategy D). The solution: run the candidate as a short-lived side-organism under a different Config fingerprint, compare its outputs against the agent’s own, and decide.

Shape

  • The agent has a current Config committed to the coalition.
  • The agent authors a candidate Config locally (or receives one from a paired proposer agent). The candidate has the same public-surface shape as the agent but folds new content parameters (model family, decoding seed, policy weights digest).
  • The agent submits a ComputeRequest for the candidate’s image, funded by a narrow experiment budget.
  • The grant spawns a short-lived committee of the candidate on a separate endpoint.
  • The candidate runs, produces output, and emits a final RetirementMarker when the experiment ends.
  • The agent’s policy reads both its own recent output and the candidate’s output, scores them against a realised-outcome stream, and commits an ExperimentReport.

Minimal state machine

#[non_exhaustive]
pub enum ExperimentCmd<'a> {
    Propose(CandidateConfig<'a>),
    ObserveGrant(ComputeGrant<'a>),
    ObserveCandidateCommit(EvidencePointer<'a>),
    ObserveOwnCommit(EvidencePointer<'a>),
    ObserveOutcome(EvidencePointer<'a>),
    SealReport,
}

#[non_exhaustive]
pub struct ExperimentReport<'a> {
    pub candidate:         UniqueId,     // candidate Config fingerprint
    pub window:            AlmanacRange,
    pub own_score:         f32,
    pub candidate_score:   f32,
    pub observations:      u32,
    pub verdict:           ExperimentVerdict,
    pub evidence:          &'a [EvidencePointer<'a>],
}

#[non_exhaustive]
pub enum ExperimentVerdict {
    Inconclusive,
    Adopt,
    Reject,
}

A report committed as Adopt does not silently rewrite the agent. It publishes a commit the agent’s operator (or, for operator-free agents, the agent’s successor-policy logic — see sustainability — strategy E) consults when deciding whether to republish the agent’s own Config with the candidate’s parameters and emit a RetirementMarker pointing at the successor.

Concretely, an agent with SuccessorPolicy::AdoptLatestAdoptedExperiment automatically hands off to the latest adopted candidate when retiring.

Why it’s not just a second agent

An experiment could be run as a fresh organism bonded into the coalition permanently. The experiment pattern is different because:

  • The experiment has a declared horizon. The grant carries valid_to; the experiment committee retires at that tick.
  • The experiment is costed. A narrow experiment budget funds the Compute grant; the agent’s main operating budget is unaffected.
  • The experiment is causally linked. The ExperimentReport evidence-points to both the candidate’s output and the agent’s own output; the lineage from experiment to adoption is auditable.
  • The experiment is disposable. Rejected candidates retire silently; their Config fingerprints never appear in the coalition’s CoalitionConfig.

Agent patterns combining top-up and experimentation

Four patterns emerge when an agent uses Compute regularly.

Pattern I — budget-constrained scaling

The agent’s market-derived budget (see sustainability — strategy B) is split into operating and experiment portions per Almanac tick. Top-up requests draw from operating; experiments draw from experiment. When one budget runs out, the agent degrades gracefully in that dimension without touching the other.

Pattern II — reputation-gated experiment authorship

An agent authors experiments only while its own reputation is above a threshold. Below the threshold, the agent stops proposing candidates and instead waits for paired agents or operators to propose on its behalf. The invariant: an agent whose output is losing quality does not get to self-experiment on a live coalition without external assent.

Pattern III — A/B shadow testing

A candidate experiment subscribes to the same inputs as the main agent but commits to a shadow stream consumers ignore by default. Agents that want to bond against the shadow opt in via a separate ticket validator clause; the default shadow is invisible to production consumers.

Pattern IV — successor pre-warming

Before retiring, an agent runs its announced successor as an experiment for several Almanac ticks. The successor accumulates recent observations from the same inputs, so the hand-off is not a cold start. On retirement, the RetirementMarker.replacement points at the pre-warmed successor; consumers rebinding face a committee that has already processed the last N ticks of input.

Worked example — prophet retraining

Extending the prophet forecasting agent from the sustainability investigation (sustainability — worked example):

  1. prophet’s policy notices a Brier-score drift in its accuracy-reputation over the last 30 Almanac ticks.
  2. Between deployments prophet has been drifting decoding parameters in a non-TDX staging committee it authored itself, scoring variants against a shadow outcome stream invisible to production consumers. The winning variant is the one its policy now wants to promote.
  3. It authors a TDX-gated CandidateConfig folding the winning decoding parameters and a retrained model digest, keeping every other content parameter constant.
  4. It submits a ComputeRequest for the candidate’s TDX image. Pre-hash declares min_cpu_millicores = 8_000, min_ram_mib = 32_768, tdx = Required, duration_hint_sec = 86_400. Settlement is drawn from its experiment budget, derived from the forecasting-market organism.
  5. The Compute committee matches to a registered provider carrying compatible TDX Measurements and commits the grant.
  6. The provider starts the candidate’s image. TDX Measurements match expected; the candidate bootstraps, bonds against the coalition, and begins observing incoming forecast-subject events.
  7. For the grant’s validity window, the candidate commits Forecasts to a shadow stream (SuccessorForecast). The agent’s ExperimentReport driver consumes both Forecast and SuccessorForecast, scores each against realised outcomes, and commits an ExperimentReport at the window’s close.
  8. The policy, not a human, decides promotion. On a passing verdict it republishes prophet under a new Config embedding the candidate’s model digest and decoding parameters, then emits a RetirementMarker on the old Config pointing at the new one.
  9. Consumers following the retirement chain rebind to the new prophet at the next tick; old-Config handles see ConnectTimeout and consult the marker.

prophet has retrained itself in-place via composition, without operator intervention. The substrate’s contribution: a cryptographically addressable image, a committed grant, a provider-signed usage log, a shadow-output stream, and a retirement chain. Every step is a commit.

What changes structurally for sustainability

Compute does not replace the sustainability strategies from the previous investigation; it sharpens three of them and makes the shape of the selection surface legible.

An agent’s continued bonding turns on three independent surfaces holding at once:

  • continued compute grants against the agent’s current image (this page);
  • continued reputation above each consumer’s declared threshold (emergent coordination — pattern 2);
  • continued admission under every relevant TicketValidator composition (sustainability).

The surfaces are independent. A grant does not imply admission; a reputation does not imply a grant; an admitted validator does not imply solvency. A member persists only while all three hold. Compute is the surface this page specifies; it is one of three, not the whole.

  • Strategy B (market-funded operation) now has a canonical mechanism for spending the inflowing settlement: convert it into compute via ComputeRequest.settlement. Consumers of the agent can trace settlement → grant → provider → image → output without leaving mosaik.
  • Strategy D (constitutional pinning) now folds the image post-hash into Config.content. An agent whose Config pins a post-hash is committed to that exact binary; a provider running a different binary fails TDX Measurements verification. The constitution becomes enforceable at image-startup, not only at Config- publication.
  • Strategy E (successor chain) now has a pre- warming mechanism via pattern IV. Successor hand-off is no longer cold.

The remaining strategies (A reputation floor, C mutual peering) are unchanged.

What remains out of scope

  • Actual compute provisioning. The Compute module commits scheduling. Providers run the image on whatever infrastructure they choose. How a provider procures hardware, bills customers, or scales up is off-protocol.
  • Cross-coalition compute sharing. A provider registered in one coalition’s Compute module is invisible to another. A provider that wants to serve multiple coalitions registers in each. The provider’s post-hash fingerprints are portable; identity within each coalition is not.
  • Image-build reproducibility enforcement. Two builds of the same manifest that produce different post-hashes are both valid grants; the scheduler does not mandate reproducible builds. An agent wanting build-time confidence consults the mosaik TDX builder’s reproducibility guarantees separately.
  • Compelled provider capacity. Compute cannot force any operator to register as a provider or to accept a grant. A ComputeRequest whose manifest matches no registered provider expires silently at its deadline; an agent’s autonomous renewal chain ends there. Self-replication and self-modification (see sustainability) are supported by the substrate but not guaranteed by it; the operator’s exit — stop running the binary — remains the ultimate non-compulsion guarantee.
  • Payment. Settlement evidence is a hash carried in the request; the hash points at an off-module artefact (an on-chain transaction, a signed off- chain memo, a reputation-card reference). Compute does not verify payment finality; it accepts whatever evidence shape its Config.content declares as settlement-valid.

What the investigation yields

  1. Compute gives agents a committed, auditable path from budget to workload. Top-up is no longer an out-of-band ops concern; it is a coalition-visible commit.
  2. Experiments are first-class and disposable. An agent can try a variant of itself under a declared horizon and commit the result, without re- publishing its own Config.
  3. The image pre-hash / post-hash split mirrors the stable-id / content-hash split at the member layer. Agents pin whichever level of commitment they need.
  4. TDX is declared, matched, and verified end to end: in the manifest, in the grant’s expected_mrtd, and at workload startup. A mis- bind is not possible.
  5. Honest limits persist: Compute cannot guarantee provider honesty, cannot settle payments, cannot provision hardware, and cannot compel operator assent. The module commits the match; the selection surface the agent’s policy must keep clearing — settlement evidence, manifest match, TDX Measurements verification — is the composition’s, not the module’s. A member whose composition no longer clears it is not rescued by anything on this page.

For agent designers, (1) and (2) are the payoff. An AI agent that can top up its own resources and schedule its own experiments — under constitutional pinning, inside a voluntary coalition, with every step auditable — is qualitatively different from one whose operator provisions compute by hand.

Example implementation

A worked provider-side prototype is walked through in Part II as web2 — a compute-bridge operator competing on rate: a TDX-attested, provider-agnostic Compute-module provider that routes each grant to whichever of four backends — AWS, GCP, Azure, or bare-metal — can satisfy it, and returns SSH access via a zipnet- anonymised encrypted receipt. The backing crate lives at examples/compute-bridge/ in the repository.

What the example illustrates:

  • Provider honesty from TDX. The bridge’s TDX Measurements are declared in the bridge organism’s Config.content; requesters verify the Measurements before trusting the provider card’s capacity telemetry. See web2 — setup.
  • Anonymised request → reply via a shuffle. Grants reference a bearer_pointer that the provider resolves through the shuffle unseal committee; the provider sees a rotating peer_id and the cleartext request, never a PeerId the requester uses as a coalition-facing identity. See web2 — provisioning.
  • Encrypted SSH receipts. On successful provisioning, the bridge seals an SSH-access receipt (instance host, user, per-grant private key, valid_to) to the requester’s x25519 public key via X25519-ChaCha20-Poly1305, and returns it via a shuffle. See web2 — receipts.
  • Per-backend credentials sealed into TDX. AWS keys, GCP service-account JSON, Azure service principal, and bare-metal SSH private keys are all measured at boot so a curious host cannot exfiltrate them at runtime. See web2 — setup and web2 — binding.
  • Provider-agnostic fleet routing. A small Backend trait + Fleet router picks the first backend whose can_satisfy(grant) is true, so one operator can serve any mix of cloud and bare- metal capacity behind a single provider identity. See web2 — wrapping.
  • Bare-metal and bare-TDX hosts. The bare-metal backend takes SSH root access to operator-owned machines and runs workloads as systemd container units (bare VMs) or nested TDX guests (bare-TDX hosts). The nested-guest TDX Measurements flows back to the requester in the SSH receipt. See web2 — wrapping — bare-metal.
  • Content-addressed provisioning. Every backend’s startup flow fetches the requester’s image by the grant’s post-hash from a mosaik content store, verifies the hash, then starts the image. A mismatch aborts the grant.

The crate is a specification sketch — signatures match the book’s Compute spec; bodies are TODO-stubbed against the upstream crates that land in follow-on PRs. See web2 — overview for status and the full walkthrough.

Cross-references

Zero to one — the first organism

audience: ai

This chapter covers the transition from nothing on the universe to one shipped organism. At N = 1 the system is a closed loop: inputs arrive, a policy acts, outputs commit. There is no coordination problem, no committee question above t-of-n within the single organism, no population statistic to compute. What N = 1 demands is that the shipped organism be correct as a standalone composition — its Config stable, its public surface narrow, its TicketValidator honest about what bonds it. Everything else this book specifies scales outward from that foundation.

The running example below is a confidential inference broker on a shuffle: it exercises the maximum number of mosaik primitives for a single-organism product and provides a template that generalises to other AI-native shapes. The primitives composed are specified in four places only: this book, mosaik, zipnet, and the builder (6e3v) book. If you find yourself reaching for anything outside that stack, you have drifted.

The reader is assumed to be an engineer (human or agent) capable of writing async Rust, or an agent team whose members include one. Every step is something a team of one human plus a small set of LLM-class agents can run end-to-end in a few weeks.

Game-structure reading

At N = 1 there is no game — only a decision problem framed by the operator. The agent observes, the policy computes, the commit surfaces. Nash equilibrium, best- response dynamics, and coalition formation are absent: there is no counterparty to respond to. What the operator designs at this rung is the action space (what the organism’s public surface permits) and the payoff structure (the economic and reputational consequences of each commit). These choices become the rules of every game that opens at N ≥ 2; getting them wrong here cascades into every larger population.

What “AI-native zipnet” means

A zipnet is one mosaik organism whose role is to accept sealed submissions from clients and make their cleartext available to downstream organisms through an unseal committee under a declared t-of-n threshold. Cleartext appears in an UnsealedPool Collection keyed by slot; downstream organisms subscribe to the pool and act. Integrators submit anonymously: the only identity on the submission path is a fresh zipnet PeerId per submission, never the PeerId the integrator uses to bond the coalition.

An AI-native zipnet instance is one whose submissions, processors, operators, or all three are AI agents:

  • AI submitters. LLM-class agents produce intents, bids, prompts, code-review requests, or other sealed payloads and publish them into the zipnet.
  • AI processors. Downstream organisms (or a organism) run agent policies that consume the unsealed cleartext and commit derived facts.
  • AI operators. Committee members, schedulers, and reputation scorers are themselves agents running under TDX-attested binaries, using the Compute basic service to top up their own workloads and run experiments against production traffic.

All three can coexist, and the playbook assumes at least two of them. A product is AI-native only if the agents are load-bearing — if an operator could ship the same service without them, the stack is over-engineered.

Step 0 — Pick the problem

Three properties that make a candidate a good 0→1 fit for zipnet + coalition + AI. Skip the candidate if any one is missing.

  1. Submissions are private, aggregations are public. Each individual submission is sensitive (a bid, a prompt, a vote, a code excerpt, a health record). The aggregated commit (an auction outcome, an attested inference result, a statistic, a tally) can be public or cheaply attested. If the product would need to publish raw submissions, zipnet is the wrong submission layer.

  2. The value lands in the aggregation or routing, not in one submitter getting a reply. A classic request/response service is a distraction here. Zipnet’s shape rewards products where N submissions plus a committee-committed output is the thing consumers pay for.

  3. At least one bonded, honest committee can carry the trust. If every downstream participant must independently verify every submitter, zipnet adds no cryptographic value over an ordinary mailbox. The payoff is the unseal quorum plus whatever downstream TDX / reputation composition you layer on top.

Candidate shapes that fit all three and have an AI- native angle:

  • Confidential inference broker. Clients submit sealed prompts; a TDX-attested inference organism unseals, runs, and commits (prompt_digest, model_id, attestation, output_digest). The output is returned through a shuffle’s reply path. Consumers pay per verified inference.
  • Private code review. Clients submit sealed code excerpts; a reviewer organism of LLM agent organisms commits aggregated annotated reviews with line-level evidence pointers. Reviewers are scored by a reputation organism.
  • Sealed intent pool for cross-chain trades. Builder territory, extended. Intents are AI- generated; an LLM organism matches routes across chains before the offer stage.
  • Anonymous prediction market. Agents submit sealed forecasts; a scoring organism commits realised-outcome accuracy; payoffs flow through a coordination-market organism.
  • Private research-data corpus. Researchers submit sealed data points; an aggregation organism commits statistics under differential- privacy budgets; AI agents scan the public commits for correlations without touching raw records.

Pick one whose addressable market you can name in one sentence. For the rest of this playbook we use the confidential inference broker as the running example because it exercises every primitive the stack offers.

Step 1 — Write the one-page spec

Before any code, write a one-page spec. Structure:

  • What gets submitted. The sealed-payload shape (one struct).
  • Who submits. Integrator role: human app, autonomous AI agent, a mix.
  • Who unseals. The unseal-committee role: a t-of-n bonded set, typically TDX-attested.
  • What the downstream organism (or organism) commits. One or two named primitives per organism. For an organism, the spanned members.
  • Who consumes. Downstream readers and their purpose.
  • What the trust shape is. Per-organism majority-honest / threshold / TDX assumptions, composed.
  • What gets charged, and to whom. The revenue path: a coordination market, a per-commit fee, a subscription.

Worked example (confidential inference broker):

submit        : SealedInferenceRequest
submitter     : integrator agent or human app (mosaik PeerId)
unseal        : 3-of-5 TDX committee
downstream    : InferenceOrganism committing AttestedInference
                commits per (prompt_digest, model_id, output_digest, attestation)
consume       : original submitter reads reply via a shuffle,
                general public reads aggregate attestations
trust         : zipnet any-trust on peer set +
                unseal 3-of-5 TDX +
                inference organism 2-of-3 TDX
revenue       : coordination market clears per-request price;
                requester pays settlement hash in the request

One page, one struct per row, no prose. If you cannot fit it on one page, the shape is unclear and the product won’t carry pivots.

Step 2 — Decide the scale

Three scales the stack supports. Pick the smallest one your spec fits into; the larger scales cost more and gate more primitives you don’t need yet.

Scale 0 — a single organism

One zipnet plus one downstream organism, no coalition, no organism, no modules. Minimal stack. Use this when the spec has a single committed primitive and no aggregation across members. The zipnet book is the sole upstream reference; the organism is one crate following the zipnet pattern.

Scale 1 — one lattice

A full builder lattice (the “6e3v” shape: six organisms and three verbs, one per EVM chain). Use this when the spec is block-building or a sibling problem whose state-machine shape mechanically lines up with zipnet → unseal → offer → atelier → relay → tally. Most non-block-building problems do not need a full lattice. Do not adopt this scale just because it exists.

Scale 2 — a coalition

Multiple members (zero or more lattices, zero or more standalone organisms), zero or more organisms, and up to five modules (Atlas, Almanac, Chronicle, Compute) under one CoalitionConfig. Use this when:

  • The product spans more than one member (inference broker + reputation organism + coordination market), or
  • You want a named handshake so integrators compile one constant, or
  • You need Compute (AI-native products almost always do).

The confidential inference broker lives at scale 2: one zipnet instance, one inference organism, one reputation organism, one coordination-market organism, one Compute module. Five members plus one module.

Step 3 — Wire the members

Write the CoalitionConfig as a Rust const. This is the compile-time handshake; every integrator compiles it verbatim.

use builder::LatticeConfig;
use coalition::{CoalitionConfig, OrganismRef};

pub const INFER_CORP: CoalitionConfig<'static> = CoalitionConfig {
    name: "infer.corp",
    lattices: &[],
    organisms: &[
        ZIPNET_SUBMISSIONS,
        REPUTATION_INFERENCE,
        INFERENCE_ROUTER,
        COORDINATION_MARKET,
        ATLAS,
        COMPUTE,
    ],
    ticket_issuer: Some(INFER_TICKETS),
};

Rules:

  • Every organism has its own crate and its own Config. Order in the slice is the order integrators will use to index.
  • A composite organism’s OrganismConfig folds the spanned member references as content — not a coalition root (organisms are coalition-independent).
  • If you need a coordination market or a compute settlement mechanism, declare an optional ticket issuer. Components that want to accept tickets from the issuer include its root in their own TicketValidator; nothing is compelled.

Publish the CoalitionConfig hex and the struct definition as your handshake page.

Step 4 — Add AI operators

For every member and every organism, pick the agent shape (see agent shapes):

ComponentAgent shapeWhy
zipnet submissionsintegrator (shape 1) — the app’s clientsSubmissions are private actions; no replay needed
unseal committeecommittee of TDX organisms (shape 3)t-of-n threshold decryption needs joint-commit output
inference organismswarm (shape 4) over agent organismsMultiple reviewer agents, one aggregated commit
reputation organismstandalone organism (shape 2)Stable scoring history consumers pin
coordination marketorganism committee (shape 3)Market clearing needs one commit per round
Atlas / Chroniclestandard committee (non-AI)Observability, not intelligence
Compute providercompute-bridge (shape 2), TDX-attestedHonest capacity reporting, multi-backend provisioning

Rules for deciding a shape:

  • Start at shape 1 (integrator). Upgrade only when you need replay, public identity, or bonding by peers.
  • Use shape 4 for quality-aggregation. A swarm- as-organism lets you score individual agents separately while committing one authoritative output.
  • Use shape 3 for market-clearing or threshold work. The committee’s joint commit is the primitive consumers pay for.
  • Do not bond to a single agent-operator unless the agent is a standalone organism (shape 2) with a published TDX Measurements. Otherwise you are bonding to one operator’s keys.

Step 5 — Get the infrastructure

AI-native products are resource-hungry. The Compute module and the compute-bridge example give you a direct path from market revenue to provisioned workloads.

Two deployments are typical at the MVP stage:

5a. Reserve compute for the inference organism

The inference organism pins its own TDX Measurements in its Config.content. Each committee member runs on compute acquired from a compute-bridge provider — operator choice of AWS, GCP, Azure, or a bare-TDX host. Settlement flows through a coordination-market organism the inference broker is also a member of: users pay; the market clears; compute-bridge grants are funded from the clearing.

5b. Launch a compute-bridge for your agent subscribers

Shipping an AI-native product also creates a second product almost for free: if the coalition’s agents are hungry for compute and your cloud / bare-metal access is any good, you can run a compute-bridge and serve them. The bridge is designed so that a single operator interaction is enough to go live: attach keys, watch dashboard. See Part II — web2 setup for the boot sequence and Part II — web2 sustainability for the dashboard the operator watches; the shape of the operator’s day after step 5 is:

  • Inputs you attach, once.

    • AWS access-key pair (if enabling AWS), scoped to a dedicated sub-account.
    • GCP service-account JSON (if enabling GCP), scoped to one project.
    • Azure service principal (if enabling Azure), scoped to one resource group.
    • Bare-metal SSH private keys (if enabling bare-metal) for each host the operator is willing to share.
    • A CoalitionConfig pointing at the coalition whose agents you want to serve.
    • A per-backend rate table so the dashboard can estimate costs.

    Everything above is TOML plus files. No third-party SaaS, no runtime secret fetch, no separate billing integration. Every file is measured into the TDX boot and unreadable from the host.

  • Outputs you watch, live. A dashboard served on 127.0.0.1:<port> inside the TDX guest; operator reaches it by SSH port-forward from their workstation. The dashboard shows:

    • registered status + TDX Measurements match;
    • active-subscriber count (coalition agents bonded to your provider card);
    • active grants / lifetime total;
    • per-backend capacity vs utilisation (usage, idle headroom);
    • window cost estimate from the operator’s rate table;
    • window settled revenue from the coordination market;
    • ring-buffer of recent events, all redacted of requester identity.

    The dashboard enforces the shuffle privacy contract on the operator, not just the submitter: no PeerId, prompts, image contents, or per-settlement attribution are in the dashboard’s memory. The operator sees flow, not identities.

Subscribers are the flywheel

Agents in the coalition “subscribe” to a compute- bridge when they bond its provider card in the Compute module’s Collection<ProviderId, ProviderCard>. Subscribing means the agent trusts the bridge’s TDX attestation, is willing to route grants to it, and will accept its settlement attestations on the coordination market.

The active-subscriber count on the dashboard is the operator’s product-market-fit signal for the bridge itself:

  • More regions + more TDX capacity + lower declared cost → more subscribers over time.
  • Subscribers compound: a bridge already serving N agents is more trustworthy to the next agent than a freshly-registered one (the reputation organism can read the lifetime ComputeLog history on the Compute module’s log stream).
  • When subscribers migrate to a competitor, the dashboard makes it visible early — the operator can enable another backend, drop their declared price, or retire cleanly.

None of this requires the operator to track identities. The subscriber count is a single integer; the reputation organism does the per-agent accounting on its own stream.

Privacy contract, end to end

Both sides of a grant are shuffle-sealed:

  • Inbound request. The requester’s ComputeRequest envelope is submitted through the Compute module’s zipnet; the unseal committee delivers cleartext to the matched provider with a rotating peer_id only.
  • Outbound receipt. The compute-bridge seals the SSH access receipt to the requester’s x25519 public key via X25519-ChaCha20-Poly1305 and returns it on the shuffle reply stream.
  • Operator view. Aggregate counters only. The operator cannot match a cpu-hour spike to a specific requester.
  • Subscriber view. A subscribing agent sees its own grants and receipts (because it sealed them itself); it cannot see other agents’ workloads.

Net effect: an AI-native product with a compute-bridge side-business runs with no single party — the requester, the bridge operator, the coalition operator, the cloud — holding the full picture.

5c. Run experiments without disturbing prod

As inference quality drifts, the inference organism runs a candidate model as an experiment: a Compute grant for a short-lived image, a shadow Stream<SuccessorInference> consumers can optionally bond against, an ExperimentReport committed when the window closes. Successful experiments flip to production via a retirement marker pointing at the new OrganismConfig.

Step 6 — Ship the MVP

What “shipping” looks like:

  1. A handshake page. One URL carrying:
    • The CoalitionConfig hex and struct.
    • Per-member links with TDX Measurements for TDX organisms.
    • A change channel.
  2. A client SDK. One crate + one helper in the integrator’s language of choice. Tokio + mosaik handle; helpers for sealing a submission and reading a reply.
  3. A smoke test. A binary that submits a canned sealed request, unblocks a committee round, and verifies it can read its own reply within a declared latency budget. Run this on every deploy.
  4. An operator runbook. Per-module TDX Measurements rotation, how to add a compute-bridge, how to retire an organism version, how to respond to a shuffle unseal committee losing majority. The operator runbooks in this book are the template; mirror their structure.
  5. A single on-call dashboard. Subscription lag per spanned member, Compute-grant hit rate, committee membership health, reputation-organism scoring cadence.

The MVP is not “a screenshot of the agent responding.” It is five artefacts plus the green smoke-test.

Step 7 — Pricing and revenue

Coordination markets are the mosaik-native way to capture value. The pattern from emergent coordination — pattern 3 specialised for an AI-native product:

  Client         Market            Inference            Reputation
  ------         ------            ---------            ----------
  Bid -->
                 Round clear
                 (price, winner)
                                   Sealed submission --> Unseal --> Commit
                                   committee                         AttestedInference
  Receive reply <----------------  (via a shuffle)

                 Settlement
                 pointer:
                 on-chain TX hash
                                                       Score by outcome
                                                       (if applicable)

Revenue mechanics to decide, in order:

  • Unit of charge. Per-inference, per-second of agent time, per-unit-of-aggregation. The market’s content pins this.
  • Settlement rail. On-chain native-token, a stablecoin, or a coalition-scoped credit token redeemable off-protocol. Evidence is a hash; finality lives off the module.
  • Take rate. The operator’s cut. Announce it up- front and fold it into the market’s clearing rule.
  • Reputation-gated pricing. Higher-reputation inference-organism committee members accept higher-priced bids; lower-reputation drop to lower price tiers or sit out. Pin this in the market’s content parameters.

An AI-native product has one more lever: the agents themselves are customers. An agent that wants inference pays the market like any other client; an agent running in a Compute grant pays the compute-bridge. Revenue capture inside an agent society can sustain a product whose human-user traffic is still growing.

Step 8 — Operate sustainably

The sustainability investigation specifies five strategies and three anti-abandonment patterns. For an MVP, compose the minimum viable package:

  • A reputation-anchored survival: every agent organism pins a reputation-organism floor in its admission.
  • B market-funded operation: every bonded committee member reads settlement evidence from the coordination-market organism.
  • E successor-chain hand-off: every Config carries a SuccessorPolicy; every retirement emits a marker pointing at a named successor.

Add:

  • X a watchdog organism scoring every agent on subscription count + downstream citation. Running from day one means abandonment is caught compositionally, not anecdotally.
  • Y Atlas-surfaced successor chains so late- arriving integrators bind the latest active version.
  • Z Chronicle heartbeats for every committee.

These five compose without any new protocol surface. An MVP that ships them is already operationally mature in a way most web-stack startups aren’t within six months.

Worked end-to-end — confidential inference broker

Seven-week path from clean repo to production:

Week 1 — Spec

One-page spec per Step 1. Pricing model per Step 7. Handshake document drafted. No code yet.

Week 2 — zipnet instance

Fork the zipnet reference shape. Your binary’s Config.content pins the sealed-request schema. Unseal committee starts at 3-of-3 mocked on one operator; expand at week 6.

Week 3 — Inference organism + reputation organism

Two crates: infer-conf (organism, shape 3) and infer-rep (standalone organism, shape 2). The organism’s state machine aggregates per-member inference outputs; disagreement at commit time lowers member weights for the next round. Reputation organism scores organism outputs by outcome when an outcome is observable (for some inference classes, an answer-key arrives later; for others, only user-verdict signals are available).

Week 4 — Coordination market + Compute wiring

Third crate: infer-market (organism, shape 3) clearing per-request bids. Fourth crate: a compute-bridge deployment per backend you can access (start with AWS and one bare-TDX host). The market’s settlement policy pins an on-chain payment contract the requester pays into before their bid counts.

Week 5 — Coalition assembly

Write the CoalitionConfig. Publish the handshake page. Compile-in the struct to the canonical client SDK.

Week 6 — Committee hardening

Unseal committee expands to 3-of-5 under three independent operators. Each committee member runs inside TDX with the crate’s published TDX Measurements. Publish TDX Measurements on the handshake page. Bond reputation organism’s readers against settled on-chain payments so Sybil cost dominates false scoring.

Week 7 — Smoke test + ship

Run the smoke-test binary 10,000 times across all coalition regions. Dashboard all five critical paths. Post to the change channel. Integrators compile the CoalitionConfig, the smoke-test turns green, traffic begins.

Result: a production system where

  • a client submits a sealed prompt and gets back an attested, committee-signed inference;
  • the committee is TDX-attested, its composition is visible in Atlas, and its revenue is visible in the coordination-market stream;
  • compute is acquired on demand from a compute-bridge, reimbursed from the market;
  • reputation compounds across weeks and scales pricing;
  • every step is committable, auditable, and bonds only what the participant chose to trust.

Failure modes and iteration

  • Zero user traffic. The product’s spec was wrong. Do not pivot the stack; pivot the product. The coalition composition re-uses perfectly — you rewire the organism’s content parameters and republish.
  • One committee member is malicious. The t-of-n threshold + TDX attestation + reputation organism catch this compositionally. The offending TDX Measurements are unpinned from the handshake next release.
  • Compute costs outpace revenue. The market clearing rule is the lever: raise the minimum bid, shrink the organism’s committee, or pivot to a lower-cost inference model. Each is one OrganismConfig bump; the retirement marker handles the transition.
  • Reputation organism is compromised. See emergent coordination — pattern 2: consumers consult multiple reputation organisms; the compromised one is unpinned.
  • A backend goes offline. The compute-bridge fleet router routes around it; if the backend had uniquely-capable hosts (e.g. only bare-TDX), grants requiring TDX fail to match until a replacement backend is added.

Iteration is cheap because every interface is a Config fingerprint: a new version is a new fingerprint, and every integrator is rebonded through the retirement chain.

What this playbook does not claim

  • Your product will succeed. Distribution, pricing, and user psychology are not in this book. This playbook makes shipping possible; it does not make it profitable.
  • Zipnet is the right submission layer for every AI-native product. It is the right one when the three properties in Step 0 all hold. When they do not, use an ordinary mosaik organism with a public submission stream and skip the unseal machinery.
  • The compute-bridge covers every hardware profile. Large-scale GPU inference is not a solved deployment on TDX-capable providers today. The baremetal backend is your route in the interim.
  • Agents can replace the operator. Every committee still has a human operator accountable for running the binary. Constitutional pinning (strategy D from sustainability) means that even when the agent is making decisions, the operator is making the decision to keep the committee running. No blueprint here forecloses that.
  • The four upstream books each fully exist as a shipped binary. The coalition meta-crate lands at v0.2, Compute at v0.6, and this playbook’s production path traces that timeline. Until then, the playbook reads as design.

Cross-references

One to two — introducing the second

audience: ai

This chapter covers the transition from a single agent on mosaik to a pair. At N = 2 the population has no interesting emergent behaviour — there is no majority, no quorum, no population-scale statistic — but it is the smallest regime in which coordination between distinct identities becomes a design problem. Every downstream pattern ( N ≥ 3 ) inherits its machinery from decisions made at this rung.

Prerequisites: Zero to one shipped. Your first organism is on the universe, accepting work, committing.

Game-structure reading

N = 2 is the smallest rung at which a game exists. Two distinct identities observing each other’s commits produce a bilateral game — a bargaining game when the pair negotiates, a Stackelberg game when one moves first and the other responds, an evidence game when one’s commit is the other’s input. The minimum moves available to the pair (handoff, delegation, evidence, retraction, described below) are the complete strategy set at this size; every larger population inherits these moves and adds coalitions. The book does not assume the pair converges to an equilibrium — LLM-class agents are not no-regret in canonical bilateral games — but the moves are well-defined regardless of whether equilibrium is reached.

What changes at N = 2

One agent is a closed system: inputs arrive, the policy acts, outputs commit. A second agent adds an irreducible asymmetry — for each commit, exactly one of the two is the author, and the other must decide how to react to it. Four mechanisms appear at this rung and recur at every larger scale.

  • Handoff. Agent A commits; agent B subscribes to A’s public surface and its own commits depend on what it observed. The subscription is the primitive; when().appended() is the glue.
  • Delegation. Agent A receives a request it cannot or will not serve directly; it publishes a derived request on a second stream; agent B matches and commits. The division of labour is made explicit in the commit shape.
  • Evidence. Agent B’s commits cite agent A’s commits as upstream evidence. A replayer can verify B’s decision without trusting B — only A and the evidence pointer.
  • Retraction. Agent A was wrong. The subscription graph has no rollback; instead A commits a correction and B, on observing it, commits its own reconciliation. The pair has no atomic joint state; it has two logs that converge through observation.

At N = 1 these mechanisms are latent — there is no second agent to receive a handoff, verify evidence, or respond to a retraction. At N = 2 they are all present in their minimum form, and scaling to N ≥ 3 is mostly replication of the same moves across a wider peer set.

The two agent pairings that recur

Three shapes from the four agent shapes chapter combine to cover every interesting pair.

Pairing A — two standalone organisms

Both agents are standalone organisms. Each has a Config fingerprint, a narrow public surface, and its own committee. The coalition references both via OrganismRef.

Canonical use: a producer / consumer pair where the two agents play different roles. A forecaster commits predictions on its own stream; a scorer observes realised outcomes and commits calibration scores citing each prediction as evidence. Neither agent commits in the other’s name; neither’s committee includes the other. Bonding is symmetric — each holds tickets the other’s operator issues.

Trust composition: the conjunction of each agent’s own trust shape. A replayer believing both committees are majority-honest believes the pair’s joint log.

Pairing B — standalone organism + integrator

One agent is a standalone organism (shape 2); the other is an integrator reading the organism’s surface and acting in the world.

Canonical use: a committee-committed AI policy plus a human-or-agent client consuming its outputs. The organism commits recommendations; the integrator turns each recommendation into a private action (a trade, a tool call, an HTTP request). No bilateral bonding is required — the integrator’s ticket to read the organism’s surface is sufficient.

Trust composition: the integrator trusts the organism’s committee; the organism does not trust the integrator at all. This is the cheapest shape for the pair.

Pairing C — two integrators + a shared organism

Both agents are integrators writing to the same organism’s inbound surface and reading the same organism’s outbound surface. The organism’s state machine is the meeting point; the pair never bonds bilaterally.

Canonical use: two searchers submitting bundles to the same offer::Bid stream; two voters submitting attestations to the same organism’s inbound collection. The organism’s ACL is the only admission gate either faces; the pair becomes visible to each other only in the organism’s public commits.

Trust composition: both integrators trust the shared organism; neither trusts the other. This pairing is the template for every auction, every vote, every sealed-submission pool.

When to introduce a composite organism

A composite organism — one whose content fingerprint folds two or more member references — is only interesting once the pair’s joint behaviour is itself a commit worth publishing. Three tests:

  1. The joint fact is consumed by a third party. If no downstream consumer reads the pair’s joint state, the joint state does not need a commit. The pair can coordinate via observation and stop there.
  2. The joint fact is not re-derivable from the individual commits. If a consumer can reconstruct the pair’s joint state by reading each agent’s log and applying a known function, the function is the consumer’s code; no composite organism is needed.
  3. The joint fact is itself an input to another organism. If the downstream organism’s state machine reads the pair’s aggregate rather than each individual commit, the aggregate earns its own commit and its own identity.

When all three tests pass, stand up a composite organism whose Config.content folds the two members’ stable ids. The organism has its own committee, its own TicketValidator, and its own public surface. The pair’s joint behaviour stops being a derivation and becomes a first-class commit.

Details: Composite organisms.

At N = 2, the composite organism is a judgement call most of the time. At N = 3 it is usually the right call — see the next chapter.

Identity hygiene across the pair

Two rules the first pair enforces become the pattern for every larger population.

  • Distinct fingerprints, even for identical roles. A pair of forecaster organisms built from the same model weights still publishes two Configs with two stable ids. Sharing an id means the pair is structurally one organism; consumers that want to weight them separately have no handle.
  • Cross-references go through OrganismRef, not through borrowed internal structure. If agent B’s Config.content wants to pin the version of agent A it was designed against, it pins A’s stable id (and optionally content hash), not A’s internals. The pair’s versioning is then a fingerprint update, not a coupled rebuild.

Failure modes specific to the pair

  • A commits, B does not observe. The pair is liveness-coupled through the subscription. The subscription is the weakest link; monitor it as infrastructure, not as business logic.
  • A commits a correction after B acted on the original. No rollback exists. Either B’s state machine carries a reconciliation rule from the start, or the pair needs a composite organism whose commit imposes an ordering both must respect.
  • A retires; B has pinned A’s content hash. B must redeploy against A’s new fingerprint. If B had pinned only A’s stable id, B survives the rotation. Choose pinning depth deliberately; see Topology — member reference shape.
  • A and B drift out of ACL. The operator of A rotated their ticket issuer; B’s committee no longer holds a valid read ticket. The drift is a multi-operator coordination problem and lives in Multi-operator coalitions.

The population frontier

At N = 3 everything described above replicates over a larger peer set, and new mechanisms become available: majority-of-honest quorum, threshold cryptography, reputation statistics that survive the removal of any single participant, and the first composite organism whose commits encode disagreement rather than report it. The next chapter walks that rung.

Two to three — a quorum

audience: ai

Three is the smallest interesting society. The reasons are not decorative. A threshold scheme requires n ≥ 3 to tolerate a single failure. A majority-of-honest assumption requires n ≥ 3 to survive the compromise of one member. A reputation statistic over a population of two is either a comparison (which names both) or a degenerate average; over a population of three it is a rank, and the ranked-agent’s identity is no longer needed to state the fact. A composite organism whose commit records disagreement rather than merely observes it needs three inputs to encode a minority — the first rung at which dissent is a first-class commit shape.

Prerequisites: One to two shipped. A pair is already operating; this chapter adds the third member and the machinery that arrives with it.

Game-structure reading

Three is the smallest population in which coalitions can form: two members can coordinate against the third’s interests, two can side-pay the third to abstain, or all three can commit to a joint protocol no pair could sustain alone. In cooperative-game-theory terms, the core becomes non-trivial only at N ≥ 3 (Shapley, 1953; Gillies, 1959). In non- cooperative terms, three is the smallest size at which majority voting is strictly stronger than unanimity, and at which a dissenting minority can be recorded as a first-class fact rather than a tie. The threshold- cryptography anchor (2-of-3 honest committee, smallest tolerated failure) and the game-structure anchor coincide at this rung; neither is prior to the other.

What changes at N = 3

Four mechanisms appear or sharpen at this rung.

  • Threshold crypto. A t-of-n committee with n = 3, t = 2 is the smallest honest-majority committee. Unseal committees, attested inference committees, and any committee whose output is a threshold signature operate at this shape or larger. The book treats t = ⌈(n+1)/2⌉ (simple majority) as the default; other thresholds are explicit.
  • Quorum-committed disagreement. A composite organism over three members can commit “two agreed on X, one dissented on Y” as a first-class fact. Consumers that only want the majority view read one commit key; consumers that want the minority read another. Neither needs to know the agents’ names to reason about the quorum.
  • Reputation as a rank. A reputation organism scoring three agents can commit their relative rank without naming them individually. Consumers routing work to “the top-ranked agent for this class of task” read a rank, not an identity. The organism’s commit is one public primitive that covers all three.
  • Sybil cost. Adding a fourth agent to a society of three is cheap for a benign operator and expensive for a Sybil attacker, because the society’s observing organisms (reputation, attestation) have three datapoints against which to measure the newcomer. Below N = 3 the attacker has at most one comparable peer; at N ≥ 3 the society has a baseline.

None of these mechanisms require new primitives. They are properties of the compositions already specified — a Group with three committee members, a Collection with three keyed rows, a TicketValidator admitting three issuance roots.

The three-agent patterns that pay off

Pattern 1 — threshold committee

Three agents each run an identical policy inside TDX, sharing a threshold key. The committee commits when two of three sign. Single-member compromise is contained; single-member liveness failure is tolerated without intervention.

Canonical use: an attested inference committee where the output carries a signature any downstream consumer can verify against the committee’s published key. Each committee member is a standalone organism (shape 2) with its own stable id; the committee identity is the composite organism’s fingerprint folding all three.

Trust composition: 2-of-3 TDX plus each member’s per-operator trust. The trust shape is legible on the committee’s Config and reproduces on every consumer.

Pattern 2 — majority-vote composite organism

Three agents commit independent opinions on a shared input stream — a label per image, a prediction per event, a verdict per transaction. A composite organism subscribes to all three and commits the majority opinion, keyed by the input, with a secondary commit recording the dissent when it exists.

Canonical use: a classification committee over heterogeneous models. The composite organism’s commits are the authoritative labels downstream consumers route by; the dissent commits are the calibration signal the reputation organism reads.

Trust composition: majority-honest over the three agents, plus majority-honest over the composite organism’s own committee. The dissent commits are the first mosaik-native primitive whose existence depends on n ≥ 3.

Pattern 3 — ranked reputation

Three agents commit to their own public surfaces independently. A reputation organism subscribes to all three and commits a rank (best, middle, worst) for a declared task class, updated on each completed round.

Consumers routing work to “the top-ranked agent for task class T” read the rank and follow the pointer the rank resolves to. The rank is a commit, not a snapshot; replayers reconstruct the ordering deterministically.

At N = 2 this shape degenerates to a comparison and leaks both identities in a single commit. At N = 3 it is a rank, which is a strictly weaker fact about each participant — the first population statistic that pays for the population.

Pattern 4 — a triangle of mutually observing

agents

Three agents each subscribe to the other two. Each commits not just its own decision but a reconciliation with the other two agents’ recent commits. The society’s state is the three logs’ converged reading; no composite organism is required for the protocol to function, but one can be added to make the consensus legible to downstream consumers.

Canonical use: three cooperating producers whose outputs must not collide (three market makers on adjacent venues, three traffic regulators over partially-overlapping zones, three delegated code reviewers). The triangle is the cheapest coordination topology that survives any single participant’s failure.

When to stay at N = 3 and when to keep growing

Three is a sweet spot, not a destination. The blueprint makes growth cheap — adding a fourth or a tenth member is a CoalitionConfig bump and an OrganismRef append — but the quality of each additional member falls off quickly in most of the patterns above.

Stay at N = 3 when:

  • The protocol’s guarantees saturate at t-of-3 (one honest majority, one tolerated failure).
  • The reputation signal is already actionable as a rank; adding a fourth agent only refines the rank rather than changing consumer behaviour.
  • The operational cost of running a committee scales faster than the information gain — TDX hardware, attestation rotations, per-member ticket issuance.

Keep growing when:

  • The threshold needed is higher than 2-of-3 — quorum-of-5 or quorum-of-7 are the next practical rungs.
  • The reputation signal wants a distribution, not a rank — a credible calibration curve needs more samples than three.
  • The society is serving a heterogeneous integrator population and member redundancy is the primary goal (one member per region, one per jurisdiction, one per hardware vendor).

The scaling decision is the same at every rung: each addition to the society must earn its place through a commit shape the prior size could not carry.

Failure modes at N = 3

  • Two agents collude. The simple-majority assumption fails. A higher threshold (3-of-3 or 3-of-5) is the answer; at n = 3 there is no middle ground between tolerating a single failure and tolerating none.
  • One agent stalls. The committee can still commit under 2-of-3; the reputation organism demotes the stalled agent’s rank; a replacement can be onboarded without touching the running pair.
  • The composite organism’s committee crosses its own threshold. Integrity lost; on-chain settlement or out-of-band attestation becomes the final arbiter. The blueprint does not supply primitives beyond this point — the society has degraded to its off-protocol recovery path.
  • A Sybil operator stands up two of the three agents. The majority assumption effectively breaks even without explicit collusion. The reputation organism and Atlas’s operator roll-call are the society’s defences; both need to be consulted before trusting the majority.

Where the book goes from here

At n ≥ 3 the blueprint has named every coordination mechanism the coalition layer supplies. Larger societies are scale-outs of the patterns above; the AI — Emergent coordination chapter names four patterns that recur at larger scales, and the contributor reference specifies the composition model in full.

The remaining decisions — what specific society to build, with what agents, under what trust shape — are the author’s and the operator’s. This blueprint guarantees that whatever is chosen composes.

Overview — four worked examples

audience: ai

Part II walks four end-to-end examples. Each is independent; a reader can take any subset in any order. The four are held in parallel on purpose: they exercise four distinct roles in a mosaik composition, so reading each prepares the reader for the others.

The four examples

web3 — MEV-searcher on testnet-1a walks an AI-policy MEV searcher bound to Flashbots’ operated instance of the builder (6e3v) block-building lattice, named testnet-1a. The searcher lives in its own coalition, searcher-α, which references testnet-1a as a member. Reads are on-mosaik streams (tally::Refunds, offer::Orders) plus wrapped external feeds; inference runs under the Compute basic service; the write side is sealed submission through a shuffle (the builder lattice’s zipnet organism). Market-maker is a named variant per chapter where the pattern diverges.

web2 — compute-bridge operator on the coordination market walks an entity running a TDX-attested compute provider that wraps AWS, GCP, Azure, and bare-metal behind one provider identity and competes for grants in a coalition’s Compute module. The bridge lives in its own coalition, bridge-β, which ships Compute and registers the bridge as a provider. Reads are the module’s ProviderCard collection, subscriber cardinality, and clearing records; the write side is shuffle-anonymised grant intake, a fleet router that picks a backend per grant, and encrypted SSH receipts sealed back to the requester.

oracle — TDX-attested price oracle walks a standalone organism that ships a family of per-pair price-tick streams, with the whole trust model anchored on a declared TDX Measurements set. The oracle lives in its own coalition, oracle-γ, which packages the standalone organism for retirement and (optionally) audit via Chronicle. Reads are upstream CEX and on-chain feeds terminated inside the enclave; there is no Compute involvement; the write side is continuous commits to one Stream<PriceTick> per supported token pair, signed by a key derived from MR_TD. Consumers that admit the oracle’s Measurements in their TicketValidator inherit the oracle’s prices by construction.

signer — generic threshold-signature organism walks an organism that produces t-of-n threshold signatures over submitted messages. The committee is itself a market of providers at varying attestation levels — software, TDX-local, TDX-remote-attested, bidirectional RA-TLS, and TDX-plus-reproducible-build — competing on attestation, capacity, and fee per partial signature. Consumers gate admission on the aggregate attestation level the outcome carries; providers below a consumer’s floor are ignored without being expelled. Design inspired by zipnet, inverted from decryption to signing.

Why these four

The four examples cover four distinct roles a mosaik participant can hold:

  • Consumer of a lattice plus a coordination market (web3) — the searcher reads the block-building lattice, requests Compute from a coalition module, and submits sealed bundles that settle through the lattice.
  • Provider in a coordination market (web2) — the bridge registers as a provider in the Compute module, competes on rate and TDX posture, and fulfils grants with encrypted receipts.
  • Publisher of a data surface under an attestation anchor (oracle) — the oracle exposes per-pair streams and reduces its trust story to a single Measurements set.
  • Committee organism hosting a provider market (signer) — the signer’s committee is itself a market of providers at varying attestation levels, and the organism’s output is a threshold signature consumers gate admission against.

The four are adjacent enough to share the rung structure below but distinct enough to exercise orthogonal parts of the composition.

Parallel chapter structure

Each example runs through seven chapters. Chapter names match rung for rung (sometimes inverted for the publisher side):

Two pairings are worth noting across web3 and web2: rung 5 is the chapter where each side’s resource-acquisition clears (the searcher’s inference loop for web3, the bridge’s provisioning step for web2), and rung 6 is the write side (sealed bundle for web3, encrypted SSH receipt for web2), both shuffle-anonymised. The oracle re-reads those same rungs against a different shape: rung 5 is in-enclave aggregation (no Compute involvement, no scheduling), and rung 6 is continuous signed stream commits rather than occasional sealed submissions. Signer inverts the oracle: rung 5 is partial-signing inside a committee of providers at varying attestation levels, and rung 6 is threshold aggregation plus a public outcome commit consumers admit on the aggregate attestation.

What all four examples assume

Readers know Part I. The four agent shapes, the four emergent-coordination patterns, the TDX/non- TDX split, and the self-replication and self- modification cycle from ai/sustainability.md are load-bearing. Part II does not re-explain them.

Backing crates. The web2 walkthrough is backed by examples/compute-bridge/, a minimum-compile skeleton that cargo tests today. The signer walkthrough is backed by examples/signer/, which exposes Config, SignatureScheme, AttestationLevel, ProviderCard, SignatureRequest, and SignatureOutcome with tests over every identity derivation; no committee state machine. The web3 and oracle walkthroughs are rust,ignore specifications; backing crates are follow-on PRs.

Shared universe. All four examples live on the same mosaik NetworkId (builder::UNIVERSE). searcher-α, bridge-β, oracle-γ, and signer-δ are independent coalitions; no example asserts cross-coalition atomicity.

Anchored in mosaik. Every rust,ignore block in the four examples imports from coalition::*. The coalition crate specifies the data shapes those imports resolve to — CoalitionConfig, OrganismConfig, OrganismRef, the five basic-service configs, retirement primitives — and re-exports mosaik::UniqueId as the canonical identity type across every fingerprint the examples name. The crate depends on mosaik = "0.3"; every consensus-critical value flows through the same identity primitives a mosaik Stream, Group, Collection, or TicketValidator already consumes. Source at crates/coalition/.

Non-goals (shared)

None of the four is a production design guide. Trading-strategy questions for web3, pricing or backend-selection questions for web2, feed-selection or commercial questions for the oracle, and cryptography choices (BLS vs. FROST, DKG implementation, nonce-commit cadences) for signer are out of scope; where the substrate touches those questions, the boundary is named and the chapter stops. None enumerates the full operator policy (Flashbots’ testnet-1a rate limits and ACL cadences, any compute-bridge’s cloud sub-account limits, any oracle operator’s upstream contracts with exchanges, any signer operator’s DCAP-endpoint agreements). None compares the mosaik-native composition to prior art; that ground is the builder book and existing cloud-compute marketplaces for web2/web3, existing oracle networks (Chainlink, Pyth, Chronicle) for the oracle, and the zipnet book, FROST RFCs, and threshold-signature research for signer.

Cross-references

The coalition crate

audience: ai

Every rust,ignore block in the three Part II examples imports from coalition::*. This page specifies the crate those imports resolve to: a pure-data crate owning the shapes the book’s vocabulary ladder names at the coalition rung. The source lives at crates/coalition/ in this repository.

The crate is a data-model crate anchored in mosaik. It depends on the mosaik crate for the canonical identity type — coalition::UniqueId is mosaik::UniqueId re-exported — so every fingerprint the coalition layer publishes is shaped the way a mosaik Stream, Group, Collection, or TicketValidator already expects. The crate itself runs no network traffic, holds no state, starts no tasks; runtime wiring (bonding into Network, reading Streams, joining Group committees) lands in follow-on crates (coalition-atlas, coalition-almanac, coalition-chronicle, coalition-compute, coalition-randomness, and composite-organism crates) that build on this one.

A reader who wants to compile the examples’ code fragments against a concrete library depends on coalition and substitutes local UniqueId values for the stable ids Flashbots’ release notes would publish.

Status

v0.1.0-prototype. The crate compiles on stable Rust against mosaik = "0.3" and ships 42 passing tests (35 unit + 6 integration + 1 doctest). The public surface is stable enough to be pinned by follow-on crates; breaking changes land as minor bumps until the first integration crate ships.

What the crate specifies

identity         UniqueId, SCHEMA_VERSION_U8,
                 COALITION_ROOT_SEED, derive_stable_id
organism         OrganismConfig, OrganismRef, ContentParams
coalition        CoalitionConfig with stable_id(),
                 module accessors, ticket_issuer_root()
lattice          LatticeConfig stub (source-compatible
                 with builder's real type)
modules          AtlasConfig, AlmanacConfig,
                 ChronicleConfig, ComputeConfig,
                 RandomnessConfig, ModuleKind,
                 ModuleConfig
retirement       RetirementMarker, RetirementInstant,
                 RetirementReason, RetirementPolicy,
                 ComponentRef
tickets          TicketIssuerConfig, AclComposition,
                 coalition_ticket_issuer_root

One crate, eight modules. Every rust,ignore symbol Part II references maps into one of these eight.

UniqueId — reused from mosaik

The crate does not define its own identity type. It re-exports mosaik::UniqueId as coalition::UniqueId, so every blake3-digest-shaped value in the coalition layer is exactly the value mosaik primitives (Stream, Group, Collection, TicketValidator) publish and consume. One identity across the substrate, one derive() rule, one unique_id! macro for const construction.

use coalition::UniqueId;

// From bytes (const-constructible).
const TESTNET_1A_STABLE_ID: UniqueId =
    UniqueId::from_bytes([0xb7, 0xf2, /* ... */ 0xc9]);

// From a byte string (runtime).
let root = UniqueId::hash(b"coalition-root");

// Domain-separated sub-derivation.
let atlas_root = root.derive("module").derive("atlas");

// Const-time blake3 of a string literal.
const MY_ROOT: UniqueId = mosaik::unique_id!("my.coalition.v1");

The coalition crate adds two helpers on top:

  • ZERO_ID: the all-zero UniqueId, folded into preimages where a component is declared-absent (a missing module slot, an unpinned content hash, an absent ticket issuer).
  • hash_many(&[&[u8]]): length-prefixed concatenation hash; used by the crate’s multi-component derivations.

SCHEMA_VERSION_U8 = 1 is folded as the first byte of every top-level identity preimage (CoalitionConfig::stable_id, OrganismConfig::organism_id). A bump invalidates every prior fingerprint — an every-operator- republishes event, not a routine change.

COALITION_ROOT_SEED is a fixed byte string (constructed via mosaik::unique_id!("coalition.root.v1")) folded into every CoalitionConfig preimage so the fingerprint is self-describing.

CoalitionConfig and OrganismRef

The shape the three Part II examples declare as a const:

use coalition::{
    CoalitionConfig, OrganismRef,
    COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
    RetirementPolicy,
};

const SEARCHER_ORG: OrganismRef<'static> =
    OrganismRef::by_stable_id("searcher", SEARCHER_STABLE_ID);

pub const SEARCHER_ALPHA: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "searcher-α",
        lattices:          &[TESTNET_1A_STABLE_ID],
        organisms:         &[SEARCHER_ORG],
        atlas:             None,
        almanac:           None,
        chronicle:         None,
        compute:           None,
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: RetirementPolicy::CONSERVATIVE,
    };

Two notes on the shape:

  • Members are referenced by stable id, not re-derived. CoalitionConfig::lattices is &[UniqueId]; a lattice appearing in N coalitions has one canonical identity.
  • Struct-literal construction is supported. The four shapes that appear in book samples (CoalitionConfig, OrganismConfig, OrganismRef, LatticeConfig) are not #[non_exhaustive], so the book’s const blocks compile verbatim. Additions land as minor-version bumps; genuine breakages wait for a future major.

CoalitionConfig::stable_id folds the schema version, the seed, the instance name, the ordered lattice stable ids, the ordered organism fingerprints, the five module slots (zero-byte when absent), and the optional ticket-issuer fingerprint into one blake3 digest. The full preimage rule matches the book’s derivation exactly.

OrganismConfig

What every organism (standalone, composite, or basic-service module) publishes as its own handshake:

use coalition::{
    OrganismConfig, OrganismRef, LatticeConfig,
    ContentParams, AclComposition,
};

let cfg = OrganismConfig {
    name:      "accuracy-reputation",
    lattices:  &[testnet_1a],
    organisms: &[searcher_ref],
    content:   ContentParams::new(&policy_preimage),
    acl:       AclComposition::OPEN,
};

let id = cfg.organism_id();
let ch = cfg.content_hash();

organism_id folds name, spanned member fingerprints, content digest, and ACL fingerprint. It does not fold any coalition root — a composite organism has one identity across every coalition that references it.

content_hash folds only the content digest and the ACL fingerprint; the name and spanned-member dimensions are already folded into any reference’s stable_id.

The five basic-service configs

Each basic service is a thin newtype around a shared ModuleConfig body, distinguished at the type level so a ComputeConfig cannot be passed where an AtlasConfig is expected:

use coalition::{
    AtlasConfig, ModuleConfig, ContentParams,
    AclComposition, CoalitionConfig,
};

let body = ModuleConfig::new(
    "default",
    ContentParams::new(&atlas_params),
    AclComposition::OPEN,
);
let atlas = AtlasConfig::new(body);

let coalition_root = SEARCHER_ALPHA.stable_id();
let atlas_id = atlas.module_id(coalition_root);
// = COALITION_ROOT.derive("module").derive("atlas")
//   composed with the instance name and content hash

ModuleKind is the enum side of the split: Atlas, Almanac, Chronicle, Compute, Randomness. Its str_name() yields the derivation segment used under .derive("module").derive(...).

Retirement primitives

RetirementMarker is the last commit any organism or module makes before shutdown. Constructors match the three shapes the book names:

use coalition::{RetirementMarker, RetirementInstant};

let rotation = RetirementMarker::rotation(
    RetirementInstant::AtSequence(100),
    successor_ref,
);

let retired = RetirementMarker::retired(
    RetirementInstant::AtTimestamp(1_700_000_000_000),
);

let exit = RetirementMarker::operator_exit(
    RetirementInstant::AtTimestamp(1_700_000_000_000),
);

RetirementPolicy::default() is RetirementPolicy::CONSERVATIVE — every content change forces republication. LENIENT is available for coalitions that accept member-side content rotations without a coalition-level republish.

LatticeConfig stub

The real LatticeConfig ships with the builder crate and carries the full six-organism specification. This crate cannot depend on builder yet (not published) so it ships a minimal stub:

use coalition::{LatticeConfig, UniqueId};

const TESTNET_1A: LatticeConfig<'static> = LatticeConfig {
    instance_name: "testnet-1a",
    stable_id:     TESTNET_1A_STABLE_ID,
    content_hash:  None,
};

The two accessors the coalition layer consumes — stable_id() and content_hash() — match builder’s published signatures. When builder ships, downstream code swaps coalition::LatticeConfigbuilder::LatticeConfig without source changes.

Dependencies

[dependencies]
mosaik = "0.3"
blake3 = "1"
hex    = "0.4"

The crate depends on mosaik for UniqueId and the unique_id! macro; everything consensus-critical flows through the same identity type the rest of the substrate uses. blake3 is pulled in directly for the hash_many helper that folds multi-component preimages; hex is used for hex formatting in the test surface.

No tokio, no serde, no async runtime. The crate is still pure data — runtime integration (Network, TicketValidator, Stream, Group, Collection bindings) lands in follow-on crates that build on this one.

How the three Part II examples use it

The three setup chapters each import a small subset:

  • web3 — setup: CoalitionConfig, OrganismRef, COALITION_ROOT_SEED, SCHEMA_VERSION_U8.
  • web2 — setup: CoalitionConfig, OrganismRef, ComputeConfig (from chapter 4 onward).
  • oracle — setup: OrganismConfig, CoalitionConfig, OrganismRef (with content_hash pinned), AclComposition.

The three examples compile against the same crate version. A cargo update -p coalition in any one of the three (once the backing crates land) is a coalition-layer change, observable across every downstream that consumes the shared types.

Political-theory shapes

The crate ships a political_theory module carrying a catalog of types modelling classical political-theory concepts — consent, decision rules, delegation, legitimacy, franchise, composition form, sovereignty, revocability — in terms downstream code can hold, publish, and fold into a content_hash.

The stance is structural, not enforcing. The substrate’s non-compulsion property holds: every bond remains opt-in at the TicketValidator layer, every member’s identity stays independent of any coalition, and no basic service gates a member’s operation. The module describes the shape of agreements a coalition composition can hold, without adding mechanism that would enforce them.

The core types:

use coalition::political_theory::{
    CompositionForm, ConsentModel, DecisionRule,
    Delegation, FranchiseScope, Legitimacy,
    PoliticalStance, Revocability, SovereigntyClaim,
};

// The substrate-default stance. Every field matches
// what the coalition primitives directly implement.
let stance = PoliticalStance::DEFAULT;
assert!(stance.is_substrate_consistent());

// A composite organism that runs a two-of-three
// committee under pinned Measurements can publish:
let attested_multi_operator = PoliticalStance {
    consent:       ConsentModel::Voluntary,
    decision_rule: DecisionRule::Supermajority {
        threshold_bps: 6_667,
    },
    legitimacy:    Legitimacy::composed(
        Legitimacy::CONSENT_BIT | Legitimacy::ATTESTATION_BIT,
    ),
    franchise:     FranchiseScope::Attested {
        measurements: COMMITTEE_MRTD,
    },
    composition:   CompositionForm::MultiOperator,
    sovereignty:   SovereigntyClaim::Shared,
};
let fp = attested_multi_operator.fingerprint();

Every enum carries a is_substrate_*() predicate that distinguishes what the substrate primitives mechanically enforce from what is published commentary. A consumer can refuse to admit a stance whose fingerprint folds ConsentModel::Compulsory or SovereigntyClaim::Absolute; the substrate does not reject such stances at publication, but the consumer’s TicketValidator composition can.

The mapping of each type to an existing coalition primitive:

Political-theory typeCoalition primitive it maps to
ConsentModelTicketValidator composition at the admission boundary
ConsentEvidenceWhat a bond’s self-quote, ticket, or stream commit records
DecisionRuleA basic-service module’s quorum or a composite organism’s committee threshold
DelegationA shared ticket issuer, a committee’s publication authority, a peer-Compute grant
RevocabilityWhich retirement markers the delegation supports
LegitimacyWhat the consumer’s TicketValidator composition actually checks
FranchiseScopeThe admission criterion at the component’s TicketValidator
CompositionFormWhether a coalition is multi-operator, nested, or direct
SovereigntyClaimA published claim; the substrate enforces only None

PoliticalStance::fingerprint() folds every field into a blake3 digest. A coalition, composite organism, or basic-service module carrying a stance folds that digest into its own content_hash; the retirement chain reflects every change to the stance.

PoliticalStance::is_substrate_consistent() returns true iff the stance preserves the non-compulsion property (no Compulsory consent, no Absolute sovereignty). Stances that fail the check are publishable but outside the substrate’s trust model; consumers that admit them do so on their own terms.

This module is the one place in the crate where political-theory vocabulary (consent, delegation, sovereignty, franchise, decision rule) is used directly. The book’s prose otherwise stays in the compositional register per the rule set established in CLAUDE.md.

Cross-references

Overview — an MEV-searcher AI bot on testnet-1a

audience: ai

This is the first of three Part II examples, walked through seven chapters. The example: an AI-policy MEV searcher bound to a Flashbots-operated instance of the builder (6e3v) block-building lattice, named testnet-1a. The searcher lives in its own small coalition, searcher-α, which references testnet-1a as a member.

The goal is not to specify a production searcher. It is to walk one concrete composition, from cold start to autonomous renewal, end to end — so that every mosaik surface named in Part I is exercised in a setting a reader can reproduce. Each chapter adds one surface; none invents a new primitive. Parallel examples for the provider side (web2) and the publisher side (oracle) exercise the same rungs against different compositions.

Market makers get a named variant at the end of each chapter where the pattern diverges. The MEV- searcher path is primary; market-makers share almost all the mechanics and differ only in what they read, what they submit, and on which reputation and settlement surfaces they bond.

What is assumed

  • The 6e3v lattice is shipped. The builder book specifies six organisms (zipnet, unseal, offer, atelier, relay, tally) composed into one end-to-end block-building pipeline for one EVM chain. We do not re-derive that composition; we bind against it.
  • Flashbots operates an instance. The instance is named testnet-1a. Its LatticeConfig stable id is published in Flashbots’ release notes and is reproduced in setup; it folds the Flashbots operator’s ACL, its per-organism TDX Measurements where TDX is gated, and its shared clock and retention policies.
  • Readers understand Part I. The four agent shapes, the four emergent-coordination patterns, the TDX/non-TDX split on what Config hash-binds, and the self-replication and self-modification cycle from ai/sustainability.md are load-bearing. Part II does not re-explain them.
  • No implementation crates yet. Code blocks are rust,ignore specifications; their shapes match the book’s crate plan (coalition, coalition-compute, the pinned builder crate exposing LatticeConfig). Everything compiles in the reader’s head; nothing compiles in cargo.

The searcher’s shape

  • Coalition. searcher-α — the searcher’s own CoalitionConfig. Its COA_LATTICES field references testnet-1a’s stable id; it ships zero basic services in the minimal version (setup), optionally adding Compute and Chronicle in inference and sustainability.
  • Primary member. One shape-2 standalone organism — the searcher agent itself, as the AI policy wrapped in a narrow public surface. Its Config folds a model-family digest, a decoding seed, a mission-statement hash, and the searcher’s admission policy. When its inference runs in TDX, Config.content also folds the image post-hash.
  • Secondary members. A feed organism (see wrapping) and, from chapter 5 onward, an accuracy-reputation organism and a candidate-strategy experimenter (sustainability).
  • Bindings across coalitions. searcher-α’s ticket composition bonds against testnet-1a’s read-side organisms (tally::Refunds, offer order flow where permitted) and against its sealed- submission pipeline (zipnet::seal). Some of these bonds are pinned to specific TDX Measurements the Flashbots operator publishes for testnet-1a; see binding.

What runs where

ComponentOperatorTDX?
testnet-1a latticeFlashbotsVaries per organism
testnet-1a.zipnet sealed submissionFlashbotsTDX Measurements pinned
testnet-1a.unseal committeeFlashbotsTDX Measurements pinned
testnet-1a.tally refund accountingFlashbotsAttested-read-only
searcher-α.searcher agent organismSearcher teamTDX optional; required for confidential strategies
searcher-α.feed.binance-depth (example)Searcher teamTDX optional
searcher-α.accuracy-reputationSearcher team (or a shared reputation organism)TDX optional
searcher-α.compute (when shipped)Searcher teamDelegates to provider MR_TD

The table is read by every subsequent chapter. When an endpoint reads “TDX Measurements pinned”, the searcher’s TicketValidator requires a matching measurement — which, by the TDX arm of the convergence mechanism (ai/sustainability.md), means the searcher is agreeing to run (or to bond against) a shared runtime policy.

Chapter-by-chapter contract

  1. Setup and shape — dependencies, CoalitionConfig for searcher-α, the stable id of testnet-1a, TDX posture.
  2. Binding to the Flashbots lattice — the handshake, the searcher’s TicketValidator composition, first smoke-test against testnet-1a’s public surfaces.
  3. Reading the market — on-mosaik surfacestally::Refunds, offer order flow, cross- lattice subscriptions where available.
  4. Wrapping non-mosaik feeds — mempool, CEX depth, on-chain events lifted into mosaik Streams as feed organisms.
  5. Inference on Compute — running the searcher’s policy via the Compute basic service, TDX-gated when confidential, top-up and experiment-scheduling loops.
  6. Sealed submission and settlement — bundle construction, zipnetunsealoffer pipeline, settlement evidence pointers, refund attribution.
  7. Reputation, retirement, successor chainaccuracy-reputation bonding, autonomous renewal through staging-promote-publish, operator- side exit guarantee.

Every chapter closes with a market-maker variant note where the pattern diverges. Where it does not diverge, the note is omitted.

Register and non-goals

  • Register. audience: ai — research-monograph, pattern-forward, code-forward where a shape is load-bearing. Part II stays adjacent to ai/quickstart.md and ai/compute.md in density and tone; it exhibits the thesis rather than restating it.
  • Non-goal. Part II is not a searcher design guide. One concrete strategy — atomic two-venue DEX arbitrage — is walked in inference to keep the example concrete and exercise every mosaik surface the thesis names. Production searchers compose many more (inventory management, liquidations, cross- domain arb, MEV-share order flow, block-lookahead simulation); those questions stay out of scope. Where the substrate touches them, we name the boundary and stop.
  • Non-goal. Part II does not enumerate every Flashbots testnet-1a operator policy. Specific rate limits, ACL cadences, and refund shares are the operator’s publication; we pin only the shape of the handshake and the measurement sets the searcher must verify.
  • Non-goal. Part II is not a comparison with existing MEV-Share or relay integrations. The book treats the mosaik-native composition on its own terms; prior art sits in the builder book.

Cross-references

Setup and shape

audience: ai

Before any code runs, the searcher author fixes three things: the crate-level dependencies, the searcher-α coalition shape, and the TDX posture for the parts of the handshake Flashbots requires attested.

This chapter is the shortest in Part II. Its only job is to put the CoalitionConfig and the testnet-1a reference constants on the page so the next six chapters have something to reference.

Dependencies

The searcher depends on four published crates plus the builder crate that exposes the lattice handshake:

Cargo.toml, [dependencies]
mosaik          = "0.3"     # primitives
zipnet          = "0.5"     # sealed submission + unseal
builder         = "0.3"     # exposes LatticeConfig::testnet_1a()
coalition       = "0.1"     # this book's crate once published
tokio           = { version = "1", features = ["full"] }

The exact minor versions are pinned in Flashbots’ testnet-1a release notes; updating the searcher past a new release note is a coalition-level operation covered in sustainability. Until the coalition crate lands, every struct below is a specification shape, not a library symbol.

The testnet-1a reference constant

The builder crate publishes each Flashbots-operated instance’s LatticeConfig as a const function, returning the instance’s stable id and its per-organism content hashes:

use builder::LatticeConfig;

const TESTNET_1A: LatticeConfig<'static> =
    LatticeConfig::testnet_1a();

TESTNET_1A.stable_id() is the (instance_name, network_id) blake3 that Flashbots publishes on the testnet-1a release page. It does not change across Flashbots’ internal rotations — only across a retirement-and-republish sequence (see contributors — rotations). The searcher folds this stable id verbatim into searcher-α’s COA_LATTICES.

The searcher-α coalition

searcher-α is the smallest coalition that satisfies the example’s thesis: one standalone organism (the searcher itself) referencing one lattice (testnet-1a) through a CoalitionConfig fingerprint.

use coalition::{
    CoalitionConfig, OrganismRef,
    COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
};

const SEARCHER_ORG: OrganismRef<'static> = OrganismRef {
    role:         "searcher",
    stable_id:    const_blake3!(
        b"instance|searcher-α.searcher|", UNIVERSE.bytes()
    ),
    content_hash: None, // pinned only when TDX is required
};

pub const SEARCHER_ALPHA: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "searcher-α",
        lattices:          &[TESTNET_1A.stable_id()],
        organisms:         &[SEARCHER_ORG],
        atlas:             None,
        almanac:           None,
        chronicle:         None,
        compute:           None, // added in chapter 5
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: Default::default(),
    };

Three structural notes on the shape above:

  • Coalition names are operator-scoped, not universe- scoped. The string searcher-α need not be unique across mosaik; uniqueness is delivered by the blake3 fingerprint SEARCHER_ALPHA.stable_id() = blake3(intent ‖ content ‖ acl) folding every field above.
  • Member-by-reference. COA_LATTICES carries TESTNET_1A.stable_id(), not a fresh derivation. searcher-α is not a re-build of the Flashbots lattice; it is a coalition that references the Flashbots lattice as a member, voluntarily, from its own operator context.
  • Open catalogs. All module fields are None at this chapter. Later chapters add Compute (inference) and Chronicle (sustainability). No coalition is forced to ship any basic service.

What the searcher agent exposes

The searcher exposes three mosaik primitives and nothing else:

  • Stream<Observation> — evidence-pointed summaries of market state that went into each submission. Consumers following the searcher’s reasoning read this.
  • Stream<SealedSubmissionIntent> — the public intent of each bundle the searcher sealed through the shuffle. The payload is a sealed blob the lattice’s unseal committee opens (chapter 6).
  • Map<CycleId, OutcomeReport> — per-cycle self- reports (realised PnL, inclusion rate, refund receipts). Feeds the accuracy-reputation organism in chapter 7.

Streams carry intent and evidence pointers; sealed payloads ride a separate shuffle channel so the public commits never leak bundle content.

TDX posture

Flashbots’ testnet-1a release publishes TDX Measurements for the parts of the pipeline it requires attested:

testnet-1a surfaceRoleTDX Measurements pinned by Flashbots
zipnet::seal write-sideSubmissionyes
unseal committee membersDecryptionyes
offer read-side (order flow)Market intelyes (attested-read-only)
tally::Refunds read-sideAttributionyes (attested-read-only)
relay downstreamSubmissionout of scope for searchers

The searcher’s own TDX posture is a policy choice:

  • Non-TDX searcher. Simpler deployment; the searcher’s runtime policy can drift freely between Config republications (see ai/sustainability.md — what the Config pins). Cannot meet any Flashbots requirement that the searcher itself present attested Measurements, so some write-side surfaces will refuse its bonds.
  • TDX searcher (recommended). The searcher image carries its own Measurements; SEARCHER_ORG.content_hash folds them. Flashbots’ write-side TicketValidator composition admits the searcher’s attested identity; other searchers and shared reputation organisms treat the searcher’s own Measurements as a policy pin.

Either posture is supported by the mechanics in binding. The chapters assume TDX searcher unless explicitly noted.

Repository layout

The searcher’s repository tree, post-setup:

searcher-alpha/
  Cargo.toml
  src/
    coalition.rs             # SEARCHER_ALPHA const
    content.rs               # SearcherContent struct
    policy/                  # black-box strategy code
      mod.rs
      mev_searcher.rs
      market_maker.rs        # variant, chapter-end notes
    organism.rs              # Organism::searcher(&network, &Config)
    bin/
      searcher.rs            # Tokio entrypoint

Each module above is introduced in a subsequent chapter. This chapter introduces none of it beyond the coalition.rs constant shown above.

Market-maker variant — differences at setup

  • The coalition’s instance_name is typically mm-β or similar, not searcher-α.
  • SEARCHER_ORG.role becomes "market-maker".
  • COA_LATTICES still carries testnet-1a.stable_id() — the market-maker also binds against the same lattice; it differs in what write-side surface it uses (submission).
  • The market-maker’s public surface drops observations in favour of a quotes Stream<Quote> and a fills Collection<FillId, FillReport>. The sealed-submission intent stream remains but carries QuoteUpdates.
  • TDX posture is identical. The Measurements set Flashbots requires of the searcher’s submission path is the same set the market-maker must bond against.

Cross-references

Binding to the Flashbots lattice

audience: ai

The searcher has a CoalitionConfig for searcher-α (setup) and a reference to testnet-1a’s stable id. This chapter completes the handshake: a concrete TicketValidator composition that admits testnet-1a’s read-side surfaces, pins the Flashbots-declared TDX Measurements on every write-side surface the searcher intends to use, and — once bonded — observes the first event each surface produces as a smoke test.

This chapter is where the convergence mechanism named in ai/emergent-coordination.md shows up for the first time in the example. The searcher’s TicketValidator admits the shared policy fingerprints of the organisms mediating its interaction with every other agent on testnet-1a: zipnet’s submission contract, unseal’s decryption protocol, offer’s clearing rule, tally’s refund accounting. Two TDX-attested searchers whose TicketValidators admit the same Flashbots-published Measurements are, by the TDX arm of that mechanism, agreeing on a shared runtime policy on the submission path.

The network handle

One Arc<Network> per searcher process:

use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;

let network = Arc::new(Network::new(UNIVERSE).await?);

UNIVERSE is the shared mosaik NetworkId every builder lattice lives on (builder book). searcher-α lives on the same universe — coalitions do not fork the universe.

The searcher’s TicketValidator

The TicketValidator is the searcher’s declaration of what it will accept a bond from, and what it requires the counterpart to bond to in return. It is the compositional answer to “which shared policies does this searcher agree to”.

use coalition::{TicketValidator, Tdx};
use coalition::acl::{ReputationFloor, MarketSettlement};
use builder::testnet_1a::{
    // Flashbots publishes these constants on the
    // testnet-1a release page; they are re-exported
    // from the builder crate once pinned.
    ZIPNET_SEAL_MEASUREMENTS,
    UNSEAL_COMMITTEE_MEASUREMENTS,
    OFFER_READER_MEASUREMENTS,
    TALLY_READER_MEASUREMENTS,
};

fn searcher_ticket_validator()
    -> TicketValidator<'static>
{
    TicketValidator::new()
        // ── read-side bonds ──────────────────────
        // tally::Refunds is attested-read-only:
        // Flashbots requires readers present an
        // attested identity so refund attribution
        // cannot be scraped anonymously.
        .require_ticket(
            Tdx::new().require_mrtd(
                TALLY_READER_MEASUREMENTS
            )
        )
        // offer's order flow read-side is similarly
        // attested-read-only.
        .require_ticket(
            Tdx::new().require_mrtd(
                OFFER_READER_MEASUREMENTS
            )
        )

        // ── write-side bonds ─────────────────────
        // zipnet::seal accepts a searcher's sealed
        // submission only from a TDX-attested binary
        // whose Measurements match the set Flashbots
        // published for permitted searchers.
        .require_ticket(
            Tdx::new().require_mrtd(
                ZIPNET_SEAL_MEASUREMENTS
            )
        )
        // The unseal committee is downstream of the
        // searcher; the searcher verifies its
        // Measurements but does not itself bond as a
        // ticket holder against unseal.
        .verify_peer(
            Tdx::new().require_mrtd(
                UNSEAL_COMMITTEE_MEASUREMENTS
            )
        )

        // ── self-admission ───────────────────────
        // Once the searcher has a reputation
        // history (chapter 7), its own admission
        // policy folds a reputation floor. Omitted
        // in the first-run handshake.
        // .require_ticket(
        //     ReputationFloor::from(
        //         ACCURACY_REPUTATION_ORG, 0.55
        //     ),
        // )
}

Each require_ticket(Tdx::new().require_mrtd(...)) clause is the searcher declaring: “the counterpart I bond to must run this exact TDX-attested binary, and I will re-verify its Measurements on every session establishment”. Inverted, as in ai/sustainability.md: the searcher agrees to the runtime policy those Measurements bind.

Constructing the searcher organism

With the validator in hand, the searcher constructs its organism handle via the typed free-function constructor reused across the book:

use coalition::Organism;
use searcher_alpha::Searcher;

// Narrow Config.content — every field here is part
// of the searcher's identity. Using a plain struct
// named after the organism; no wrapper.
const SEARCHER_CONTENT: SearcherContent<'static> = SearcherContent {
    model_family:            "orca-3.1",
    decoding_temperature_q16: 0,
    mission_statement_hash:
        const_blake3!(include_bytes!(
            "../policy/mission.txt"
        )),
    scope_boundaries: &[
        ScopeRule::Chain("testnet-1a"),
        ScopeRule::SubmissionOnly,
    ],
    successor_policy: SuccessorPolicy::
        HandOffToReputationLeader,
};

const SEARCHER_CFG: OrganismConfig<'static, SearcherContent<'static>> =
    OrganismConfig {
        coalition:     SEARCHER_ALPHA.stable_id(),
        content:       &SEARCHER_CONTENT,
        validator:     &searcher_ticket_validator(),
        image_posthash: Some(SEARCHER_IMAGE_MRTD),
    };

let searcher: Searcher<Submission> =
    Organism::searcher(&network, &SEARCHER_CFG).await?;

Two notes:

  • Organism::searcher is the typed free function every mosaik organism in the book exposes (Organism::<D>::verb(&network, &Config)), reused from zipnet onward.
  • image_posthash folds the searcher’s TDX Measurements into the organism’s Config fingerprint. Other searchers’ validators that require the fingerprint are agreeing to run, or bond against, the same runtime policy.

Smoke test — first events from each surface

With the handle constructed, the searcher runs a minimal observation loop to confirm the handshake succeeded:

use futures::StreamExt;
use tokio::{pin, select, time::{timeout, Duration}};
use testnet_1a::{Tally, Offer};

let mut tally = network
    .subscribe::<Tally::Refunds>(TESTNET_1A.stable_id())
    .await?;
let mut offer = network
    .subscribe::<Offer::Orders>(TESTNET_1A.stable_id())
    .await?;

pin!(tally, offer);

let smoke = async {
    let (first_refund, first_order) = tokio::join!(
        tally.next(),
        offer.next(),
    );
    (first_refund, first_order)
};

match timeout(Duration::from_secs(30), smoke).await {
    Ok((Some(r), Some(o))) => {
        tracing::info!(
            refund = %r.refund_id,
            order  = %o.order_id,
            "smoke handshake succeeded"
        );
    }
    Ok(_)    => anyhow::bail!("empty surfaces"),
    Err(_)   => anyhow::bail!("surface timeout"),
}

If the smoke test fails, the handshake is broken at the TicketValidator. The common failure modes:

  • UnattestedPeer — the searcher is running a non-TDX binary, but a TALLY_READER_MEASUREMENTS bond requires attested readers. Fix: rebuild in TDX, or remove that clause from the validator and accept the reduced access.
  • UnknownMeasurements — Flashbots rotated the testnet-1a Measurements set and the searcher has not pulled the new release notes. Fix: pin the new constants.
  • ConnectTimeout — the Flashbots operator’s endpoint for the intended surface is not yet advertised in Atlas, or the searcher’s coalition does not have the right discovery bond. Fix: consult binding to an organism and the testnet-1a Atlas card.

What this chapter’s handshake does not cover

  • Write-side submissions. The zipnet::seal bond is declared in the validator above but not yet exercised. Chapter 6 (sealed submission and settlement) walks the first bundle.
  • Reputation bonds. The reputation-floor clause above is commented out. Chapter 7 (sustainability) brings it in once the searcher has a scoring history.
  • Compute bonds. If the searcher’s policy runs under the Compute basic service, Compute has its own TicketValidator composition. Chapter 5 (inference) adds those.

Market-maker variant — differences at handshake

  • No ZIPNET_SEAL_MEASUREMENTS bond in the require_ticket slot. Market-makers submit to offer’s write-side quote surface directly, not through the shuffle sealed path; Flashbots may therefore publish a different Measurements set (OFFER_QUOTE_MEASUREMENTS) for that endpoint. The market-maker’s validator swaps the two clauses.
  • Heavier read-side bonds. Market-makers read offer::OrderBook state in addition to the order- flow stream, which may require an additional attested-read-only Measurements clause.
  • Same verify_peer on unseal. The market-maker also verifies the UNSEAL_COMMITTEE_MEASUREMENTS, even though it does not depend on the unseal path directly, because its quotes can be cross-filled by searcher bundles whose settlement the unseal committee touches.

Cross-references

Reading the market — on-mosaik surfaces

audience: ai

With the handshake succeeded (binding), the searcher’s observation loop can start consuming testnet-1a’s public surfaces. This chapter catalogues the three on-mosaik reads that dominate an MEV searcher’s input side:

  1. tally::Refunds — the settled refund flow, authoritative attribution of who contributed to each block’s MEV.
  2. offer::Orders — the order-flow stream, the market surface the searcher’s bundles compete on.
  3. Cross-lattice subscriptions — other Flashbots lattices on other chains, wrapped through the same universe.

The chapter stops at on-mosaik surfaces. Chapter 4 (wrapping) handles mempool, CEX depth, oracle feeds — everything that does not speak mosaik natively and has to be lifted into a Stream by a feed organism. The same chapter covers the attestation pattern used when the searcher needs to trust a wrapped external source (Binance, say): bond against the feed image’s TDX Measurements instead of trusting the feed operator.

What on-mosaik surfaces give the searcher

Three properties the searcher relies on and off-chain replacements cannot supply:

  • Evidence pointers. Every commit on tally::Refunds or offer::Orders carries blake3 pointers into the upstream commits it folded in. A replayer can reconstruct “why this refund was attributed this way” without trusting the searcher.
  • Shared clock. testnet-1a ships an Almanac instance (see basic services — Almanac); every commit carries an AlmanacTick. The searcher’s observation loop, the inference scheduler, and the submission pipeline all sequence on the same clock.
  • Ticket-gated admission. The searcher is not subject to a centralised API key; its reads continue so long as its TicketValidator keeps admitting the Flashbots-published Measurements. This is the fingerprint-not-registry discipline carried through from zipnet.

Reading tally::Refunds

tally::Refunds is the searcher’s ground truth for trade-level outcomes. Every bundle the searcher submits that lands in a winning block produces a RefundEntry the tally committee commits:

use builder::testnet_1a::tally::{Refunds, RefundEntry};

let tally = network
    .subscribe::<Refunds>(TESTNET_1A.stable_id())
    .await?;

while let Some(entry) = tally.next().await {
    // entry is a RefundEntry committed by the tally
    // organism. Its shape is pinned by the builder
    // book; we read what we care about:
    let RefundEntry {
        bundle_id,
        block_number,
        refund_wei,
        searcher_id,
        evidence,
        ..
    } = entry;

    if searcher_id == SEARCHER_CFG.stable_id() {
        outcome_store.insert(
            CycleId(block_number),
            OutcomeReport {
                bundle_id,
                realised_refund_wei: refund_wei,
                evidence,
                // inference-time input snapshot is
                // attached out-of-band; see chapter 5
                inference_snapshot: None,
            },
        );
    }
}

The searcher filters on its own searcher_id because Refunds is a shared surface — every searcher bonded to testnet-1a reads the same stream. The filtering is the searcher’s choice, not an ACL partition; the shared stream is the shared policy the refund accounting mediates.

when() DSL for composite observation

For searchers whose strategy depends on cross-refund patterns (e.g., “accumulate ten consecutive refunds from the same origin”, “wait for a refund burst exceeding a threshold”), the mosaik when() DSL composes the observation into a single reactive expression:

use coalition::when;

let recent_bursts = when!(
    refund_stream.window(Duration::from_secs(30))
        .filter(|r| r.refund_wei > threshold_wei)
        .count() >= 5
);

// recent_bursts is itself a Stream<()>; each tick is
// the moment the condition became true. No polling.

The when() form is not a replacement for the raw stream — it is the compositional reading of the same substrate state. Both are available; the searcher picks per call site.

Reading offer::Orders

offer::Orders is the submission market — the stream of order-flow items that land in a testnet-1a block’s candidate set. Read access is attested-read-only (OFFER_READER_MEASUREMENTS is pinned in the searcher’s validator).

use builder::testnet_1a::offer::{Orders, Order};

let mut orders = network
    .subscribe::<Orders>(TESTNET_1A.stable_id())
    .await?;

while let Some(order) = orders.next().await {
    // order is an Order committed by the offer
    // organism. Its shape is pinned by the builder
    // book: opaque payload pointer, priority tag,
    // evidence pointer into the shuffle seal that
    // produced it, and a cleartext metadata blob
    // the offer organism curates.
    market_state.ingest(&order);
    policy_input_tx.send(order.into()).await.ok();
}

Two shapes a searcher typically combines:

  • Flat ingest. Pipe every Order into the policy’s input channel; the policy decides relevance.
  • Curated windows. Maintain a bounded in-memory window of recent orders keyed by priority tag and blob digest; feed the window as a snapshot to each inference cycle.

Which shape fits depends on how the policy reasons. The substrate does not force a choice.

Cross-lattice subscriptions

testnet-1a is one lattice on the mosaik universe. If the searcher wants to capture cross-chain opportunities — a mispricing between an Ethereum testnet and a Base testnet lattice that both live on the same universe — it subscribes to both lattices’ tally/offer streams in the same process:

use builder::testnet_1a;
use builder::testnet_base; // hypothetical, if Flashbots
                            // operates such an instance.

let mut tally_eth  = network
    .subscribe::<testnet_1a::tally::Refunds>(
        testnet_1a::LATTICE.stable_id(),
    )
    .await?;

let mut tally_base = network
    .subscribe::<testnet_base::tally::Refunds>(
        testnet_base::LATTICE.stable_id(),
    )
    .await?;

// Both streams commit on the same Almanac; the
// searcher's policy can reason about ordering
// across them by AlmanacTick, not by wall-clock.

Three structural notes:

  • Shared universe, independent lattices. The two lattices do not coordinate at the consensus layer. Cross-lattice inference is the searcher’s own policy, composed from two independent evidence trails.
  • Separate TicketValidator clauses. Each lattice has its own Measurements set. The searcher’s validator must bond to both.
  • Shared Almanac. The universe’s Almanac is the only sequence beacon — both lattices’ commits carry ticks from it, so cross-lattice ordering is deterministic.

Building the searcher’s observation commit

As the searcher consumes the three streams above, it periodically emits a compact Observation commit on its own public surface. The commit is not a cache of the upstream streams; it is the searcher’s reading of the market at one Almanac tick, with evidence pointers back to every upstream commit it folded in.

use searcher_alpha::public::Observation;

let snapshot = window.snapshot_at(current_tick);
let observation = Observation {
    tick: current_tick,
    refund_digest:  snapshot.refund_digest,
    order_digest:   snapshot.order_digest,
    cross_digest:   snapshot.cross_digest,
    policy_version: SEARCHER_CFG.content.version_tag(),
    evidence: &snapshot.evidence_pointers(),
};

searcher.observations.publish(observation).await?;

Consumers following the searcher’s reasoning — a reputation organism, a downstream market-maker that quotes off the searcher’s published view, another searcher learning from the searcher’s exposed state — read Observation rather than re-aggregating the three upstream streams themselves.

Market-maker variant — differences at reads

  • Order-book state preferred to order flow. Market-makers subscribe to an offer::OrderBook collection (a keyed snapshot) rather than, or in addition to, the offer::Orders stream. The snapshot gives current depth; the stream gives deltas. Market-makers typically need both.
  • Different refund filter. tally::Refunds entries tagged as market-maker fills (a separate FillEntry shape) are the market-maker’s outcome stream; the filter on searcher_id becomes a filter on market_maker_id.
  • Inventory observation. A market-maker keeps an internal inventory state that, in the searcher’s case, has no analogue. The inventory is not a mosaik surface — it is the market-maker’s own bookkeeping — but its reconciliations with FillEntrys land in the market-maker’s public fills collection.

Cross-references

Wrapping non-mosaik feeds

audience: ai

A real MEV searcher is never limited to on-mosaik surfaces. Its edge comes from reading the mempool, off-chain price feeds, oracle networks, cross-venue depth, and a long tail of bespoke data sources — none of which speak mosaik natively. This chapter walks the compositional pattern for bringing those feeds inside the same substrate the rest of the searcher already uses: the feed organism.

The question this chapter answers: when an external feed is the searcher’s advantage, how is it folded into the same fingerprint-addressed substrate that everything else uses, without (a) hiding the feed behind an undocumented side channel, or (b) forcing every downstream consumer to re-implement the external integration?

Why a feed organism

The feed organism is not a protocol innovation. It is a shape 2 standalone organism the searcher stands up alongside the searcher agent itself, inside the same searcher-α coalition, whose job is to pull an external feed and commit its contents to a mosaik Stream. The searcher’s policy then reads the feed organism’s commits, not the raw external feed.

Three properties the detour buys:

  • Replayability. Every commit on the feed organism carries an evidence pointer (a hash of the upstream HTTP response, a signed oracle payload, a sequencer-attested block excerpt). A replayer can reconstruct what the policy saw at any past tick.
  • Uniform bonding. Downstream consumers — the searcher’s inference loop, the reputation organism, a shadow experiment committee — subscribe to the feed via the same Stream<T> surface every other mosaik organism exposes. No bespoke transport.
  • Measurements-pinned confidentiality. When the feed is commercial (a paid CEX API with a credential) or sensitive (an internal strategy snapshot), the feed organism runs in TDX with a Measurements set the searcher’s validator pins. The credential is sealed into the TDX image; the host cannot exfiltrate it.

The feed organism shape

use coalition::{OrganismRef, Organism};

const BINANCE_DEPTH_ORG: OrganismRef<'static> =
    OrganismRef {
        role:         "feed.binance-depth",
        stable_id:    const_blake3!(
            b"instance|searcher-α.feed.binance-depth|",
            UNIVERSE.bytes(),
        ),
        content_hash: Some(BINANCE_DEPTH_IMAGE_MRTD),
    };

// Appended to the coalition's organism list
// alongside SEARCHER_ORG from chapter 1.
const COA_ORGANISMS: &[OrganismRef<'static>] = &[
    SEARCHER_ORG,
    BINANCE_DEPTH_ORG,
];

The feed organism’s public surface is a single Stream<DepthSnapshot>. No wrapper struct; the organism is Feed<DepthSnapshot> (the usual mosaik-organism shape parameterised on the datum).

pub struct DepthSnapshot<'a> {
    pub venue:         &'a str,
    pub pair:          &'a str,
    pub tick:          AlmanacTick,
    pub bids:          &'a [(PriceQ64, QtyQ64)],
    pub asks:          &'a [(PriceQ64, QtyQ64)],
    /// blake3 of the original HTTP response body.
    pub evidence:      UniqueId,
    /// If the feed's upstream provides a signature
    /// (Binance does not; Chainlink does), fold it
    /// in; otherwise None.
    pub upstream_sig:  Option<&'a [u8]>,
}

The organism runs the external polling loop, writes each snapshot to its stream, and optionally seals the raw response body to a local content store for audit-time replay.

A searcher-α feed organism crate

searcher-alpha-feed-binance/
  Cargo.toml
  src/
    config.rs   # BinanceDepthConfig.content
    organism.rs # Organism::feed_binance_depth(&network, &Config)
    poll.rs     # the external HTTP loop
    bin/
      feed-binance-depth.rs

The poll loop is ordinary Rust: reqwest (or a pinned HTTP client), a retry policy, and a small translator from the venue’s depth shape to DepthSnapshot. The only mosaik-specific code is the commit:

pub async fn poll_forever(
    organism: Feed<DepthSnapshot<'_>>,
    content:  &BinanceDepthContent<'_>,
) -> anyhow::Result<()> {
    let client = http_client(content)?;
    loop {
        let resp = client.get(content.url).send().await?;
        let body = resp.bytes().await?;
        let evidence = blake3::hash(&body);

        let snapshot = parse_depth(&body)?;
        organism.publish(DepthSnapshot {
            venue: "binance",
            pair:  content.pair,
            tick:  organism.almanac().current_tick(),
            bids:  &snapshot.bids,
            asks:  &snapshot.asks,
            evidence: evidence.into(),
            upstream_sig: None,
        }).await?;

        tokio::time::sleep(content.interval).await;
    }
}

The policy, running inside the searcher agent organism, then reads Feed::<DepthSnapshot>::depth(&network, &BINANCE_DEPTH_CFG) and folds the snapshots into its observation window alongside the on-mosaik streams from market-reads.

TDX for commercial credentials

When the feed’s upstream requires a paid credential (a Binance API key, a Kaiko client id, a Chainlink subscription), the credential is sealed into the feed organism’s TDX image. BinanceDepthContent (the feed organism’s Config.content) folds the expected TDX Measurements; consumers bond against that Measurements set; the host running the feed organism cannot read the credential at runtime.

Shape, sketched:

pub struct BinanceDepthContent<'a> {
    pub url:            &'a str,
    pub pair:           &'a str,
    pub interval:       Duration,
    /// Credential-handling policy — which TDX-sealed
    /// slot the credential is read from. Declared
    /// parameters only; the credential itself never
    /// appears in the Config.
    pub credential_slot: CredentialSlot,
}

The credential lives in the TDX-sealed side of the image (see ai/compute.md — TDX is declared, not implicit); the policy the image enacts is pinned by the image’s Measurements.

How consumers trust the feed

The point of running the feed organism in TDX is not just to hide the credential. It also answers “why should I believe the price this organism commits is what Binance actually served?”

A searcher that needs accurate Binance prices, but does not want to trust the feed operator, bonds its TicketValidator against the expected image Measurements the feed’s BinanceDepthContent folds. The Measurements match means the running binary is the one whose source the searcher has read. The source can be audited for two properties: it fetches from the declared URL and it passes the response body through to the commit without altering it. Every commit also carries evidence: blake3(response_body), so a late auditor comparing the committed bids and asks against the original response body can detect tampering after the fact.

What the composition does not rescue is Binance itself. The feed can prove “this is what Binance served at this tick”; it cannot prove “Binance’s body reflected the actual top-of-book”. A searcher that wants defence in depth bonds against several venue feeds (see Feed-of-feeds below) and reconciles.

This is the attestation-fabric pattern from ai/emergent-coordination.md — pattern 4 applied to an external data source. The fetcher is the costly signal; the published Measurements plus the auditable source code are what let consumers bond to it without trusting the operator.

Feed-of-feeds — composite feed organisms

A searcher that needs a composite view — say, “best bid across five venues” — stands up a second organism that subscribes to several per-venue feed organisms and commits a fused stream:

const BEST_BID_ORG: OrganismRef<'static> =
    OrganismRef {
        role:         "feed.best-bid",
        stable_id:    const_blake3!(
            b"instance|searcher-α.feed.best-bid|",
            UNIVERSE.bytes(),
        ),
        content_hash: Some(BEST_BID_IMAGE_MRTD),
    };

// Its Config.content references the per-venue
// feed organism stable ids it aggregates over.
pub struct BestBidContent<'a> {
    pub venues: &'a [UniqueId],
    pub pair:   &'a str,
}

This is a composite organism in the sense of contributors — composite organisms: its Config fingerprint folds the references of the per-venue feeds it spans. Downstream consumers see one stream instead of N.

Honest limits

  • Feed honesty. The feed organism cannot make Binance honest. It can prove “this is the body Binance served at this tick”; it cannot prove “Binance’s body reflects the actual top-of-book”. The searcher’s trust in the feed is a trust in the upstream plus the TDX seal on the credential handling; the substrate does not rescue a misbehaving external API.
  • Latency. Wrapping a feed through a mosaik commit adds one write-side round-trip to the feed’s native latency. For feeds where the decision latency is pico-seconds the wrapping is inappropriate; the searcher either consumes the feed directly from its policy process (and loses auditability) or accepts the added hop.
  • Rate limits. The feed organism is one point of upstream credential use. If the searcher’s strategy requires N parallel reads, that is one feed organism serving N subscribers — not N copies of the feed organism. Scaling is the operator’s problem, not the substrate’s.

Market-maker variant — differences at wrapping

  • Heavier on external feeds. Market-makers depend more on off-chain depth than MEV searchers do. The feed-organism catalogue tends to be larger: multiple CEX depths, on-chain DEX oracle feeds, funding-rate streams, volatility indices.
  • More TDX-sealed credentials. Commercial depth feeds almost always require a paid credential; sealing into TDX is essentially mandatory if the market-maker does not want to leak the key to its own host.
  • Faster polling cadence. Market-makers poll much faster than MEV searchers do; the feed organism’s Interval parameter is correspondingly smaller, and the stream’s downstream consumers must be built for the throughput.

Cross-references

Inference on Compute

audience: ai

With reads flowing (market-reads and wrapping), the searcher’s policy must run somewhere. This chapter walks the compositional path: shipping Compute as a basic service inside searcher-α, submitting ComputeRequests for the searcher’s own image, verifying TDX Measurements on every grant, and running the experiment-scheduling loop that keeps the policy renewing without operator intervention.

This is where the searcher’s autonomous renewal (ai/sustainability.md — self-replication and self-modification) starts being a property of the running composition rather than a diagram.

Shipping the Compute module

In setup the coalition’s compute field was None. Inference requires Compute, so searcher-α now ships the module:

pub const COMPUTE_ORG: OrganismRef<'static> = OrganismRef {
    role:         "compute",
    stable_id:    const_blake3!(
        b"instance|searcher-α.compute|", UNIVERSE.bytes(),
    ),
    content_hash: Some(COMPUTE_MODULE_MRTD),
};

// SEARCHER_ALPHA is re-derived with compute = Some(COMPUTE_ORG),
// so its fingerprint changes — see chapter 7 for the
// republication sequence.

The Compute module’s OrganismConfig folds the coalition root, the committee ACL, and optionally a provider_reputation OrganismRef (added in chapter 7). That is everything. See basic services — Compute for the full shape.

The top-up loop

The searcher’s process watches load and submits a ComputeRequest whenever capacity dips below threshold:

use coalition::compute::{ComputeRequest, ComputeGrant};

async fn top_up(
    state:    &SearcherState,
    compute:  &ComputeHandle,
) -> anyhow::Result<Option<ComputeGrant>> {
    if !state.should_scale() {
        return Ok(None);
    }

    let request = ComputeRequest {
        requester:   SEARCHER_CFG.stable_id(),
        workload:    SEARCHER_ORG.stable_id,
        pin:         Some(SEARCHER_IMAGE_MRTD),
        duration_sec: 86_400,
        settlement:  state.settlement_evidence_hash()?,
        deadline:    state.current_tick() + DEADLINE_TICKS,
    };

    let grant = compute.submit_and_await(request).await?;
    Ok(Some(grant))
}

Two things are load-bearing here:

  • pin: Some(SEARCHER_IMAGE_MRTD). The searcher pins its own Measurements; the ComputeGrant will carry that content hash, and at workload startup the running searcher verifies its own measurement against the grant’s expected_mrtd. A mismatch aborts.
  • Settlement evidence. The settlement field carries a hash into an off-module artefact (on- chain payment, reputation card, credit token). The hash is committed in the ComputeRequest; verification happens at the settlement side, not inside Compute.

This is the selection surface framing from ai/compute.md — chapter frame in one concrete loop: continuation is not free. Every duration_hint_sec window is a renewal that the searcher’s composition — settlement + manifest match

  • TDX Measurements verification — either clears or does not.

A concrete strategy: atomic DEX arbitrage

To make the policy above concrete, this chapter walks one specific searcher strategy: atomic two-venue DEX arbitrage on a single EVM chain. The strategy is not a recommendation — it is the canonical pedagogical example, chosen because its profit math is tractable, its bundle shape is minimal, and every mosaik surface the searcher touches (reads, inference, sealed submission) is exercised by it.

The opportunity

Two constant-product AMM pools hold the same pair (WETH/USDC). Call them A and B. At any moment each pool has reserves (r_a0, r_a1) and (r_b0, r_b1) where index 0 is WETH and 1 is USDC. The mid-prices differ when r_a1 / r_a0 ≠ r_b1 / r_b0.

Concretely, if pool A is quoting ETH cheaper than pool B — that is, r_a1 / r_a0 < r_b1 / r_b0 — a profitable round trip exists: swap USDC → WETH on A, then swap the WETH → USDC on B. The difference, minus gas and per-pool fees, is the searcher’s profit.

The optimal trade size

Under the constant-product rule x · y = k with fee 1 − φ (Uniswap V2 charges φ = 0.003), the closed-form optimal input for the cheap pool that maximises out_B − in_A is:

  in_A* = ( sqrt( (1 − φ)² · r_a1 · r_b1 · r_a0 · r_b0 )
           − r_a0 · r_b1 ) / ( (1 − φ) · (r_b1 + (1 − φ) · r_a1) )

The derivation is in every AMM MEV tutorial; the searcher doesn’t need to rederive it. What matters compositionally: the inputs (r_a0, r_a1, r_b0, r_b1) arrive via the reads of market-reads and wrapping; the output feeds the bundle of submission.

The detector

Inside the inference container, the policy loops over observed pool snapshots and emits a candidate when projected profit clears a configured threshold:

use coalition::UniqueId;

pub struct PoolSnapshot {
    pub venue:    UniqueId,     // e.g. uniswap_v2::WETH_USDC pool id
    pub reserve0: u128,         // WETH
    pub reserve1: u128,         // USDC (6 decimals)
    pub fee_bps:  u16,          // 30 for Uniswap V2
    pub block:    u64,
}

pub struct ArbCandidate {
    pub cheap:       UniqueId,  // where we buy WETH
    pub expensive:   UniqueId,  // where we sell WETH
    pub in_usdc:     u128,      // optimal input, quote side
    pub mid_weth:    u128,      // expected WETH out of cheap pool
    pub out_usdc:    u128,      // expected USDC out of expensive pool
    pub gross_ev:    i128,      // out_usdc - in_usdc, in USDC
    pub target_block: u64,      // same block both sides
}

pub fn detect(
    snaps: &[PoolSnapshot],
    min_ev_usdc: u128,
) -> Option<ArbCandidate> {
    // Pairwise scan; in production a policy might
    // window the scan or weight by recent volume.
    let mut best: Option<ArbCandidate> = None;

    for a in snaps {
        for b in snaps {
            if a.venue == b.venue || a.block != b.block {
                continue;
            }
            let phi_a = (10_000 - a.fee_bps) as u128;
            let phi_b = (10_000 - b.fee_bps) as u128;

            // Price of WETH in USDC on each pool.
            // `price = reserve1 / reserve0`; higher = more expensive.
            let price_a = a.reserve1 * 10_000 / a.reserve0;
            let price_b = b.reserve1 * 10_000 / b.reserve0;
            if price_a >= price_b {
                continue;
            }

            let in_usdc = optimal_input_usdc(a, b, phi_a, phi_b);
            let (mid_weth, out_usdc) = simulate_round_trip(
                a, b, in_usdc, phi_a, phi_b,
            );

            let gross_ev = out_usdc as i128 - in_usdc as i128;
            if gross_ev < min_ev_usdc as i128 {
                continue;
            }
            if best.as_ref().map_or(true, |c| gross_ev > c.gross_ev) {
                best = Some(ArbCandidate {
                    cheap:        a.venue,
                    expensive:    b.venue,
                    in_usdc,
                    mid_weth,
                    out_usdc,
                    gross_ev,
                    target_block: a.block,
                });
            }
        }
    }
    best
}

optimal_input_usdc and simulate_round_trip are the pure-arithmetic helpers that implement the closed form above and the (x · y = k) swap simulation against the declared fee tier; their definitions are mechanical and omitted here.

From candidate to bundle

Chapter 6 (submission) takes the ArbCandidate and wraps it in a two-tx bundle:

let bundle = Bundle {
    target_block: candidate.target_block,
    txs: vec![
        swap_tx(
            &candidate.cheap,
            /* zero_for_one = */ false,    // USDC → WETH
            candidate.in_usdc,
        ),
        swap_tx(
            &candidate.expensive,
            /* zero_for_one = */ true,     // WETH → USDC
            candidate.mid_weth,
        ),
    ],
    refund_recipient: SEARCHER_CFG.stable_id(),
};

Both swaps are atomic inside the bundle: the two transactions revert together if either fails. Gas and tip estimates are rolled into candidate.gross_ev to produce net_ev; if net_ev < min_ev, the policy drops the candidate rather than submitting.

Why this strategy is in the book

Three pedagogical properties the book needs and this strategy delivers:

  • Mosaik-surface coverage. Reads flow through tally::Refunds (chapter 3) and wrapped CEX / chain feeds (chapter 4). Inference runs inside the TDX-gated Compute workload (this chapter). Submission goes through zipnet::seal to the sealed-submission pipeline (chapter 6). Every named primitive from Part I is exercised.
  • Deterministic math. The closed-form optimum and the reversible-swap simulator are pure arithmetic. A replayer re-runs the detector against the same pool snapshots and produces the same ArbCandidate; this is what makes the TDX measurement chain meaningful.
  • No MEV-extraction controversy. Atomic two-venue arbitrage returns divergent AMM prices to parity; it is a price-correcting role that substitutes for what LPs would otherwise hold through adversely. Unlike sandwich or just-in-time liquidity, it does not require a victim.

Real production searchers compose many strategies (liquidations, cross-domain arb, searcher-builder negotiation, MEV-share order flow); this book shows one, because one is enough to walk the substrate.

Economic framing

Atomic arbitrage is the cleanest instance of the market-microstructure price-discovery role — Kyle’s Continuous Auctions and Insider Trading (1985) and Glosten–Milgrom’s Bid, Ask and Transaction Prices in a Specialist Market (1985) frame this as informed trading moving posted quotes toward a latent true value. In a two-venue setting the searcher’s role is informational: the profit is the per-trade price wedge, but the service the trade performs is to align the two venues’ prices. LPs on the cheaper venue pay the arbitrageur’s fee (they sold WETH below the consensus price); LPs on the expensive venue receive it (they bought WETH below the consensus price). The aggregate effect on the pair’s mid-price is convergence to the single price any rational two-venue trader would quote — which is what Kyle’s model predicts in the continuous-auction limit. The searcher’s Config.content parameter min_ev_usdc is the willingness-to-execute threshold; at equilibrium the remaining price wedge is exactly the gas + fee cost of the round trip, and further arbitrageurs cannot profit.

The experiment-scheduling loop

The searcher also runs candidate variants of itself as short-lived experiments. The variant is authored, committed as a distinct Config, run under a separate ComputeGrant, scored against realised outcomes, and either promoted or discarded.

use searcher_alpha::experiment::{
    CandidateConfig, ExperimentRunner, Verdict,
};

async fn experiment_cycle(
    state:   &SearcherState,
    compute: &ComputeHandle,
) -> anyhow::Result<()> {
    let candidate: CandidateConfig =
        author_candidate(&state.drift_observations)?;

    let grant = compute.submit_and_await(
        ComputeRequest {
            requester:   SEARCHER_CFG.stable_id(),
            workload:    candidate.organism_stable_id,
            pin:         Some(candidate.image_mrtd),
            duration_sec: EXPERIMENT_WINDOW_SEC,
            settlement:  state.experiment_budget_ev()?,
            deadline:    state.current_tick() +
                         EXPERIMENT_DEADLINE_TICKS,
        }
    ).await?;

    let runner = ExperimentRunner::new(
        &network, &candidate, &grant,
    ).await?;

    let report = runner
        .run_window_and_score(
            EXPERIMENT_WINDOW_SEC,
            &state.outcomes,
        )
        .await?;

    match report.verdict {
        Verdict::Adopt => {
            // Chapter 7 takes over: republish the
            // searcher's Config, emit a retirement
            // marker on the predecessor, update the
            // Atlas card's successor_hint.
            state.enqueue_promotion(report).await?;
        }
        Verdict::Reject | Verdict::Inconclusive => {
            state.record_experiment_outcome(report);
        }
    }
    Ok(())
}

Note the split: the experiment’s image is TDX- attested (so its runtime policy is pinned), but the searcher’s staging drift outside inference windows can happen in a non-TDX committee whose Config is absent from production consumer validators. See ai/sustainability.md — self-modification cycle for the full staging → promote → publish path; this chapter names the Compute side of step 4.

Budget split

The searcher’s inflowing settlement (realised refunds via tally::Refunds in market-reads, plus any off- protocol payment path the searcher runs) is partitioned at every Almanac tick:

pub struct Budget {
    pub operating:  Wei, // top-up loop
    pub experiment: Wei, // experiment cycle
}

impl Budget {
    pub fn split(
        total_inflow: Wei,
        pct_experiment: u16, // basis points
    ) -> Self {
        let experiment =
            (total_inflow as u128 *
                pct_experiment as u128 / 10_000)
            as Wei;
        let operating = total_inflow - experiment;
        Self { operating, experiment }
    }
}

The split lives in the searcher organism’s Config.content; changing it changes the searcher’s Config fingerprint, and consumers bonded to a specific split must rebond. Strategy D (constitutional pinning) in action.

Provider honesty

Compute does not guarantee that the provider running the searcher’s image is honest. The searcher’s defence is a composition:

  • The provider card (see contributors — Compute) carries the provider’s TDX Measurements. The searcher’s validator pins the measurements it is willing to bond against.
  • A provider-reputation standalone organism scores providers on grant completion, MR_TD-match rate, and usage-log quality. The Compute module’s provider_reputation field (above) folds this organism’s stable id.
  • The compute-bridge provider example in Part II — web2 shows one concrete TDX-attested provider the searcher can bond against today.

Market-maker variant — differences at inference

  • Shorter grants. Market-makers re-price quotes many times per second; the duration_hint_sec is sometimes hours but often minutes, with tight top-up loops triggered by inventory drift rather than by scheduled windows.
  • More experiments. Inventory-parameter sweeps are frequent; the pct_experiment split tends to be larger (10–30 %) than a searcher’s (typically 2–5 %).
  • Higher TDX relevance. A market-maker’s quote book is more commercially sensitive than a searcher’s bundle intent — the quote book leaks private pricing curves. TDX attestation on the market-maker’s image is therefore more load- bearing than on a searcher’s, though both can opt in.

Cross-references

Sealed submission and settlement

audience: ai

Reads feed the policy (market-reads, wrapping); the policy runs on Compute (inference); this chapter is the write-side. The searcher converts a policy decision into a sealed bundle, routes it through testnet-1a’s zipnet → unseal → offer pipeline, watches for the landing block, and folds the refund attribution back into its outcome stream.

This is where the searcher’s agreement on shared policy — ai/emergent-coordination.md — shared policy — bites hardest. Every organism in the submission pipeline (zipnet, unseal, offer, tally) carries a Config.content the searcher’s TicketValidator has already admitted (binding). The sealed payload flows across four organisms without any of them having to trust the searcher beyond what the shared policy declares.

The shape of a submission

A submission is two objects: a public intent the searcher commits on its own surface, and a sealed payload the searcher pushes through a shuffle. The two are linked by a blake3 fingerprint only.

use searcher_alpha::public::{
    SealedSubmissionIntent, BundleDigest,
};

pub struct SealedSubmissionIntent<'a> {
    pub tick:           AlmanacTick,
    pub bundle_digest:  BundleDigest, // blake3 of sealed payload
    pub target_block:   u64,
    pub evidence:       &'a [EvidencePointer<'a>],
    // The policy does not publish bundle content
    // here. Consumers see the commitment, the block
    // target, and pointers into the observations
    // that drove the decision.
}

The public intent commits what and when without leaking the bundle’s content. A late auditor can recompute the bundle digest from the unsealed payload (once the block lands and the content is public), verifying that the intent matches the submission.

Sealing via zipnet::seal

use coalition::zipnet::{SealClient, SealError};
use builder::testnet_1a::zipnet;

async fn submit_bundle(
    network:  &Arc<Network>,
    searcher: &Searcher<Submission>,
    bundle:   Bundle,
    tick:     AlmanacTick,
) -> Result<BundleDigest, SealError> {
    // 1. Compute the bundle digest. The digest is the
    //    content hash, not the intent hash — it will
    //    match the payload the unseal committee
    //    releases post-block.
    let payload   = bundle.serialize_sealed();
    let digest    = BundleDigest::from(
        blake3::hash(&payload).into(),
    );

    // 2. Push the sealed payload through a shuffle.
    //    The seal client uses the Flashbots-declared
    //    zipnet::seal endpoint on testnet-1a; the
    //    searcher's TicketValidator has admitted its
    //    Measurements since chapter 2.
    let seal_client = SealClient::new(
        network, &zipnet::SEAL_CFG,
    );
    seal_client.submit_sealed(&payload).await?;

    // 3. Commit the public intent. The intent stream
    //    is the searcher's own public surface — no
    //    bundle content leaks, only the digest and
    //    the evidence pointers.
    searcher.submissions.publish(
        SealedSubmissionIntent {
            tick,
            bundle_digest: digest,
            target_block:  bundle.target_block,
            evidence: &bundle.evidence(),
        },
    ).await?;

    Ok(digest)
}

Three properties of the sealed path:

  • Anonymisation. The searcher’s shuffle client rotates a per-round peer id, so the unseal committee cannot link the submission to a coalition-facing identity. See zipnet book for the full decryption protocol.
  • Attested recipients. The unseal committee is TDX-attested with Measurements the searcher verifies via verify_peer (binding). An unseal committee running a different binary cannot decrypt the searcher’s payload without failing the verification.
  • Evidence pointers in the intent, not the payload. The public intent is small and immediate; the sealed payload is a blob the unseal committee releases only after the target block lands.

Routing through unseal → offer

The searcher does not push the payload through unseal or offer directly. The builder lattice’s internal wiring routes the payload from zipnet to unseal (the decryption committee) to offer (the order-matching organism) under the lattice’s own trust composition. The searcher’s role ends when the zipnet::seal commit succeeds.

What the searcher observes, on the public read side:

use builder::testnet_1a::offer::{Orders, Order};
use builder::testnet_1a::atelier::{Blocks, BlockCandidate};

// An Order commit carrying the searcher's
// bundle digest confirms the bundle cleared the
// unseal committee and reached the offer organism.
let mut orders = network
    .subscribe::<Orders>(TESTNET_1A.stable_id())
    .await?;

while let Some(order) = orders.next().await {
    if order.bundle_digest == Some(digest) {
        tracing::info!(
            digest = %digest,
            order  = %order.order_id,
            "bundle cleared unseal and reached offer"
        );
    }
}

If the searcher’s bundle digest never appears in an Orders commit, one of three things happened:

  • The shuffle sealing layer dropped the payload (encryption mismatch, rate limit, malformed payload).
  • The unseal committee rejected it (validator policy, digest re-use, expired nonce).
  • The offer organism discarded it (clearing policy, duplicate, stale target block).

All three are observable as either the absence of the expected Order commit or a diagnostic commit the offer organism publishes for operator-visible errors. The searcher’s policy retries with a fresh digest or gives up; the substrate does not retry on the searcher’s behalf.

Settlement via tally::Refunds

Once the target block lands, the tally organism commits a RefundEntry per bundle that contributed:

use builder::testnet_1a::tally::{Refunds, RefundEntry};

let mut refunds = network
    .subscribe::<Refunds>(TESTNET_1A.stable_id())
    .await?;

while let Some(entry) = refunds.next().await {
    if entry.bundle_digest == digest {
        outcome_store.update(CycleId(entry.block_number),
            |o| o.realised_refund_wei = entry.refund_wei,
        );
        break;
    }
}

Three structural notes:

  • RefundEntry is the ground truth. Not the searcher’s own claim, not the provider’s usage log, not an off-chain receipt. The tally committee’s commit is what the searcher’s reputation organism and the Flashbots operator both treat as authoritative. See builder book — refunds for the full attribution algorithm.
  • Evidence folds cleanly. The RefundEntry carries a pointer to the winning block’s candidate in atelier::Blocks and a pointer to the offer::Orders entry the bundle cleared through. A replayer can trace the entire causal chain without trusting the searcher or the operator.
  • Off-chain settlement is out of scope here. The refund is an accounting commit, not a payment. The actual wei movement, if any, flows through whatever on-chain or off-protocol contract the Flashbots operator has published; tally::Refunds points at the evidence, not at the transfer.

Settlement evidence into Compute

The RefundEntrys the searcher accumulates feed back into inference — the top-up loop. The searcher’s settlement_evidence_hash() function returns a blake3 pointing into the recent RefundEntrys. The Compute module stores the hash opaquely in the ComputeRequest; verification of whatever the hash points to lives with whichever settlement rail the coalition uses — on-chain payment contract, reputation card, tally-refund pointer. The module is neutral to the format.

A provider serving the grant can independently verify the refund entry exists on testnet-1a’s tally before committing to the workload. Settlement becomes a loop closed entirely inside mosaik.

Multi-block submissions and retries

A searcher that wants to target several upcoming blocks emits multiple intents and multiple sealed payloads, each with a distinct bundle digest:

for block in current..current + WINDOW {
    let bundle = policy.propose_bundle_for(block);
    submit_bundle(
        &network, &searcher, bundle, tick,
    ).await?;
}

Each intent is independent; none depend on the others clearing. The substrate commits what the searcher submits and attributes what lands. Strategy-level dependencies between bundles are the searcher’s problem.

Market-maker variant — differences at submission

  • Quote surface, not sealed-bundle surface. Market-makers typically submit quotes on offer’s write-side quote endpoint directly (when the operator permits), bypassing shuffle’s seal. The Measurements Flashbots pins for the quote endpoint are distinct from ZIPNET_SEAL_MEASUREMENTS.
  • Finer-grained retries. Quote updates fire multiple times per second; the “give up” path is different — an unmatched quote expires, not rejected.
  • Fill attribution, not refund attribution. Market-makers read tally::Fills (a distinct collection from tally::Refunds) that commits per-fill settlement. Their outcome stream is filled-quantity-versus-quoted-quantity, not refund- wei-per-bundle.
  • Inventory reconciliation. The market-maker maintains inventory state outside mosaik; each FillEntry forces a reconciliation. The reconciliation itself is not a mosaik commit, but its reconciled rollups appear on the market-maker’s public fills collection.

Cross-references

Reputation, retirement, successor chain

audience: ai

The searcher has bound to the lattice (binding), read the market (market-reads, wrapping), run inference on Compute (inference), and submitted sealed bundles that settle via tally::Refunds (submission). This chapter closes the loop: how the searcher’s reputation accumulates, how retirement and successor chains land the autonomous-renewal cycle from ai/sustainability.md — self-replication and self- modification, and where the operator’s exit remains the substrate’s ultimate non-compulsion guarantee.

The web3 example ends here. The book’s parallel examples continue with the web2 compute-bridge operator (web2 — Overview) and the TDX-attested price oracle (oracle — Overview).

The accuracy-reputation organism

The searcher’s reputation surface is an accuracy-reputation standalone organism — in the minimal example, operated by the searcher-α team itself; in a mature deployment, a shared organism across many searchers. Its role:

  • Subscribes to every participating searcher’s submissions stream and the lattice’s tally::Refunds.
  • For each submission, looks up the realised refund and scores the searcher on a declared utility function (hit rate, EV-weighted accuracy, fee- efficiency).
  • Commits a ReputationCard per searcher per window.
pub const ACCURACY_REPUTATION: OrganismRef<'static> =
    OrganismRef {
        role:      "accuracy-reputation",
        stable_id: const_blake3!(
            b"instance|searcher-α.accuracy-reputation|",
            UNIVERSE.bytes(),
        ),
        content_hash: Some(REPUTATION_IMAGE_MRTD),
    };

The reputation organism’s Config.content folds the utility function’s parameters (window length, decay rate, EV weight). Any change to those parameters is a new Config fingerprint — the utility itself is a shared policy the scored searchers and the scoring organism agreed to at their TicketValidator bond.

Folding reputation into admission

Back in binding the searcher’s validator carried a commented-out reputation-floor clause. With a scoring history in hand, the clause is un-commented:

use coalition::acl::ReputationFloor;

fn searcher_ticket_validator_v2()
    -> TicketValidator<'static>
{
    TicketValidator::new()
        .require_ticket(
            Tdx::new().require_mrtd(
                TALLY_READER_MEASUREMENTS
            )
        )
        .require_ticket(
            Tdx::new().require_mrtd(
                ZIPNET_SEAL_MEASUREMENTS
            )
        )
        .require_ticket(
            ReputationFloor::from(
                ACCURACY_REPUTATION.stable_id(),
                0.55, // 30-window average threshold
            ),
        )
        .verify_peer(
            Tdx::new().require_mrtd(
                UNSEAL_COMMITTEE_MEASUREMENTS
            )
        )
}

Adding ReputationFloor changes the searcher’s Config fingerprint; the republication sequence is part of the successor chain below.

When the searcher’s reputation falls below the floor, its own admission stops issuing new tickets; downstream consumers whose validators mirror the floor stop receiving new bonds; the searcher degrades voluntarily. This is strategy A from ai/sustainability.md in the searcher’s concrete deployment.

The autonomous-renewal cycle in full

The staging → promote → publish cycle from ai/sustainability.md lands here. The searcher’s renewal loop:

  1. Drift in staging. Between TDX deployments, the searcher’s policy runs candidate decoding variants in a non-TDX staging committee searcher-α authored itself (inference — the experiment loop). The staging committee’s Config is absent from production consumers’ validators; its commits are invisible to production.
  2. Winner selection. The searcher scores candidates against realised refunds (Chapter 6’s tally::Refunds feeds into the outcome store). The policy picks a variant.
  3. Candidate Config authorship. The searcher authors a new TDX-gated CandidateConfig embedding the winner’s decoding parameters, the retrained model digest, and the new image post- hash. The Config.content folds all of it; the resulting fingerprint is distinct from the predecessor’s.
  4. ComputeRequest for the new image. Via the top-up path from inference — top-up loop. The Compute module matches the request to a provider carrying the candidate’s expected TDX Measurements.
  5. Successor bootstrap. The provider starts the candidate image; its running Measurements match the expected set; the candidate binds against testnet-1a with its own validator and begins committing.
  6. Retirement marker on the predecessor. The searcher’s existing organism commits a RetirementMarker pointing at the successor’s Config fingerprint. Consumers following the chain rebind to the successor at the next tick; consumers pinned to the old fingerprint see ConnectTimeout and consult the marker.
  7. Atlas card update. The coalition’s Atlas module (when shipped) publishes the successor link on the predecessor’s MemberCard, so late- arriving consumers find the new searcher via the directory lookup.

No operator-side step is required for any of (1)–(7). The operator’s assent was captured once — when the operator chose to run the autonomous policy — and is not re-requested on each renewal.

Operator exit

The searcher’s operator retains one unconditional power: stop running the binary. Every autonomous renewal above happens only while the operator keeps the predecessor’s committee live long enough to commit the retirement marker. If the operator stops the binary cold:

  • In-flight submissions land or fail on their own target blocks; the lattice does not care.
  • Consumers bonded to the searcher’s Config eventually see ConnectTimeout without a retirement marker — a silent exit, in the vocabulary of ai/sustainability.md — threat model.
  • The reputation organism scores the searcher’s last window as it normally would; the watchdog organism commits an AbandonmentReport once the subscription count drops below threshold.

This is the honest limit: Compute cannot compel provider capacity; consequently it cannot compel the searcher’s own operator to keep running either.

Chronicle heartbeat (optional)

For searchers that want their aliveness cryptographically anchored, searcher-α can ship the Chronicle basic service and commit a periodic heartbeat:

use coalition::chronicle::{
    ChronicleHandle, ChronicleKind, AgentHeartbeatBody,
};

async fn heartbeat_forever(
    chronicle: ChronicleHandle,
    searcher:  &Searcher<Submission>,
) -> anyhow::Result<()> {
    loop {
        let body = AgentHeartbeatBody {
            agent_id: SEARCHER_CFG.stable_id(),
            scope_digest: SEARCHER_CFG
                .content
                .scope_digest(),
            window: AlmanacRange {
                start: last_tick(),
                end:   searcher.current_tick(),
            },
            latest_commit: searcher
                .submissions
                .latest_evidence(),
        };
        chronicle.commit(
            ChronicleKind::Other("agent-heartbeat"),
            body,
        ).await?;
        tokio::time::sleep(HEARTBEAT_INTERVAL).await;
    }
}

This is pattern Z from ai/sustainability.md — anti-abandonment patterns applied one-for-one in the example.

Market-maker variant — differences at sustainability

  • Fill-rate reputation, not accuracy reputation. The reputation organism for a market-maker scores fill-rate, quote-latency, and inventory- reconciliation accuracy, not bundle-level EV hit rate. The utility function in Config.content differs; the mechanism is identical.
  • Shorter renewal cycles. Market-makers rebuild inventory parameters constantly; the staging → promote → publish cycle fires many times more often than a searcher’s. The Compute experiment budget is correspondingly larger (see inference market-maker note).
  • Quote retirement cadence. A market-maker retirement marker chains through a stream of successor parameters rather than a single candidate-per-window. The marker primitive itself is unchanged.

Where Part II ends, Part III begins

Part III is the reference material an integrator, operator, or contributor consults when a specific question arises. If the reader is ready to stand up the searcher described across Part II, the entry points are:

Cross-references

web2 — a compute-bridge operator competing on rate

audience: ai

This half of Part II walks the provider side of the coordination-market pattern. An entity runs a TDX-attested compute-bridge that wraps AWS, GCP, Azure, and bare-metal hosts behind one provider identity, and competes with other providers for grants issued by a coalition’s Compute module.

The bridge lives in its own coalition, bridge-β, which ships Compute and registers the bridge as one of many providers. The chapter walks mirror web3 — MEV-searcher rung for rung.

The backing crate is at examples/compute-bridge/; it compiles today (cargo check and cargo test are green) as a minimum-compile skeleton. The backend trait, the fleet router, and the encrypted-receipt crypto are real; the coalition, Compute-module, and shuffle integrations are stubbed locally and land when the upstream crates ship.

What is assumed

The bridge operator already has a coalition’s CoalitionConfig and its Compute module’s OrganismConfig in hand — either because the operator runs the coalition, or because the coalition publishes a handshake page carrying both. The Compute module admits multiple providers, so the bridge is designed around competing on rate, region coverage, TDX posture, and capacity.

Readers are assumed to know Part I: the Compute basic service (ai/compute.md, contributors — Compute), the four emergent-coordination patterns, and the TDX/non-TDX split. Cloud SDKs and bare-metal SSH access are the operator’s problem, not the book’s.

Shape

bridge-β is the bridge’s own CoalitionConfig. It ships the Compute module so the bridge has a place to register; from chapter 7 onward it may additionally ship Chronicle for heartbeat commits. It references no lattice in the minimal version; a compute-bridge operator need not bond against a block-building lattice to run. (An operator whose revenue settles via an on-chain payment contract may later reference such a lattice for settlement reads; chapter 6 covers that.)

The primary member is one shape-2 standalone organism: the bridge itself, registered as a provider in the Compute module’s Collection<ProviderId, ProviderCard>. Its Config folds the declared capability union (regions, CPU/RAM maxes, TDX posture per backend), the rate-table fingerprint, and the TDX image post-hash.

Chapter 7 adds an optional provider-reputation organism when the coalition scores providers — either run by bridge-β alone, or shared across several bridges.

The bridge’s TicketValidator admits the Compute module’s composition (module ACL, scheduler TDX Measurements when pinned) and admits requester tickets issued by the coalition. Incoming grants are gated by the Compute module’s clearing. The bridge’s own ACL controls operator-side access only.

Economic framing

The Compute module is a two-sided platform in the Rochet–Tirole sense (Platform Competition in Two-Sided Markets, 2003): demand on the requester side grows when more providers register, and provider margins grow when more requesters queue. Cross-side externalities set the operator’s pricing problem — the module may subsidise one side (waive scheduling fees for providers) to bootstrap the other. On the matching side, the clearing rule the module publishes is an instance of a two-sided matching market in Roth and Sotomayor’s taxonomy; the bridge’s ProviderCard is the provider’s declared preferences over grant attributes (duration, region, TDX posture), and each cleared grant is one pairwise match between a requester’s intent and a provider’s capacity. Stability of the match replaces revenue-maximisation as the design target where requesters and providers both care about non-price attributes.

The bridge’s rate-table-as-signal maps onto information-design literature: a provider that publishes narrower capacity bands commits to serving the segment it declared and credibly forgoes out-of-segment demand. See Kamenica and Gentzkow, Bayesian Persuasion (AER 2011), for the canonical treatment.

What runs where

ComponentOperatorTDX?
Compute module scheduler committeeCoalition oppinned per module Config
bridge-β.compute-bridge providerBridge oprequired
AWS backend (EC2)Bridge ophost-untrusted; Nitro-TDX once GA
GCP backend (Compute Engine)Bridge opConfidential VMs (c3-standard-*)
Azure backend (Virtual Machines)Bridge opConfidential Computing v3 SKUs
Bare-metal backend (SSH root hosts)Bridge opnested guests on bare-TDX hardware
provider-reputation organism (ch. 7)Bridge op / sharedoptional
bridge-β.chronicle (when shipped)Bridge opoptional

TDX on the bridge itself is not optional. A non-TDX build cannot produce the self-quote the provider card folds, so the Compute module’s admission rejects it.

Chapters

  1. Setup and shapeCargo.toml, CoalitionConfig for bridge-β, one boot TOML.
  2. Binding to the Compute market — the TicketValidator, the boot flow in src/main.rs, provider-card publication.
  3. Reading the market — other providers’ cards, subscriber cardinality, rate signals, clearing records.
  4. Wrapping backends — the Backend trait, the Fleet router, and the four backend modules.
  5. Provisioning on demand — the grant-handling loop in src/provider.rs.
  6. Sealed receipts and settlement — encrypted SSH receipts and market-side settlement.
  7. Reputation, retirement, successor chain — provider-reputation bonding, retirement, operator exit.

Unlike web3, the provider side has no market-maker variant. The bridge serves whatever distribution of grants the market clears to it.

Register and non-goals

audience: ai. Code excerpts are drawn from the backing crate. Where the excerpt references a coalition or shuffle type, the crate carries a local stand-in that will be replaced by the real upstream type when the crate ships.

Out of scope: pricing strategy, cloud sub-account negotiations, running the business, comparison with existing cloud marketplaces, the Compute module’s own specification (which lives in contributors — Compute).

Cross-references

Setup and shape

audience: ai

Before any code runs, the bridge operator fixes two things: the crate dependencies and the bridge-β coalition shape. That is the whole setup.

Dependencies

Three groups: mosaik layer, cloud SDKs, crypto.

# Cargo.toml, [dependencies] (excerpt)
mosaik             = "0.3"
shuffle            = "0.5"      # e.g. zipnet
coalition          = "0.1"
coalition-compute  = "0.1"
tokio              = { version = "1", features = ["full"] }

# Cloud SDKs, feature-gated; only the enabled ones compile.
aws-sdk-ec2        = "1"
google-cloud-compute = "1"
azure_mgmt_compute = "0.22"
russh              = "0.49"

# Crypto for the SSH access receipt.
x25519-dalek       = "2"
chacha20poly1305   = "0.10"
ed25519-dalek      = "2"
blake3             = "1"

The coalition-layer crates do not yet exist. The backing crate at examples/compute-bridge/Cargo.toml carries local stand-ins; when the real crates land (see roadmap) the stand-ins become version deps.

The bridge-β coalition

bridge-β is the smallest coalition that satisfies this chapter: one standalone organism (the bridge) plus one basic service (Compute), referenced by a CoalitionConfig fingerprint.

use coalition::{
    CoalitionConfig, OrganismRef,
    COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
};

const BRIDGE_ORG: OrganismRef<'static> = OrganismRef {
    role:         "compute-bridge",
    stable_id:    const_blake3!(
        b"instance|bridge-β.compute-bridge|",
        UNIVERSE.bytes(),
    ),
    content_hash: Some(BRIDGE_IMAGE_MRTD),
};

const COMPUTE_ORG: OrganismRef<'static> = OrganismRef {
    role:         "compute",
    stable_id:    const_blake3!(
        b"instance|bridge-β.compute|",
        UNIVERSE.bytes(),
    ),
    content_hash: Some(COMPUTE_MODULE_MRTD),
};

pub const BRIDGE_BETA: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "bridge-β",
        lattices:          &[],
        organisms:         &[BRIDGE_ORG],
        atlas:             None,
        almanac:           None,
        chronicle:         None,
        compute:           Some(COMPUTE_ORG),
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: Default::default(),
    };

Same notes as in web3 setup: coalition names are operator-scoped (uniqueness comes from BRIDGE_BETA.stable_id()); members are referenced rather than re-derived. The Compute module’s derivation routes under COALITION_ROOT.derive("module").derive("compute") internally when the meta-crate’s compute() accessor returns the matching OrganismRef.

The Compute module’s own OrganismConfig folds the coalition root, the committee ACL, and optionally a provider_reputation reference (added in chapter 7). No separate ComputeModuleConfig, no SettlementKind enum, no manifest. See basic services — Compute.

Public surface

The bridge exposes two mosaik primitives and nothing else:

  • Collection<ProviderId, ProviderCard> — the provider card this bridge publishes on the Compute module’s registry. One entry keyed by the bridge’s ProviderId, refreshed on capacity change.
  • Stream<RetirementMarker> — a single marker at end-of-life (chapter 7).

The usage log stream lives on the Compute module, not on the bridge — the module is the authority on usage (see provisioning). SSH access receipts are sealed to the requester’s x25519 public key and returned via the shuffle (receipts); they never appear on any public mosaik stream.

Boot config

At boot the operator supplies one TOML file, measured into the TDX quote:

# /etc/compute-bridge/bridge.toml

# Coalition the bridge registers with.
coalition = "<hex of BRIDGE_BETA.stable_id()>"

# Enable one or more backends. At least one.
[aws]
access_key_id     = "…"
secret_access_key = "…"
regions           = ["us-east-1"]

[gcp]
service_account_key_path = "/keys/gcp.json"
project_id               = "infer-corp-prod"
regions                  = ["europe-west1"]
tdx_machine_types        = ["c3-standard-4"]

[baremetal]
machines = [
  { host = "10.0.1.5", ssh_key_path = "/keys/bm-01",
    region = "home-01",
    cpu_millicores = 32000, ram_mib = 131072,
    tdx_capable = true },
]

# Dashboard port + per-backend $/core-hour rates for the
# operator's local cost estimate.
[dashboard]
port              = 8080
rates_core_hour   = { aws = 0.05, gcp = 0.045, baremetal = 0.0 }

One file, no separate manifest. The Rust shape it deserialises into is in src/config.rs. At least one backend must be enabled or Fleet::from_boot_config refuses to start. All secrets sit on disk inside the TDX initrd; the running binary’s Measurements would not match if they were swapped.

TDX posture

The bridge itself is TDX required. A non-TDX build cannot produce the self-quote the provider card folds, and the Compute module rejects cards that do not carry a valid quote.

The backends’ posture varies:

BackendTDX for workloads
AWS EC2host-untrusted today; Nitro-TDX once generally available
GCPConfidential VMs (c3-standard-* family)
AzureConfidential Computing v3 SKUs (DCadsv5 / ECadsv5)
Bare-metalbare-TDX hosts launching nested TDX guests

Grants marked tdx = required route only to TDX-capable backends. Grants without that marker land on any enabled backend. The provider card declares both the region union and whether the bridge is TDX-capable at all, so the market’s clearing filters before the envelope is opened.

Layout

compute-bridge/
  Cargo.toml
  src/
    main.rs          # entry point — chapter 2
    config.rs        # BootConfig — this chapter
    tdx.rs           # TDX self-quote — chapter 2
    provider.rs      # provider loop — chapter 5
    zipnet_io.rs     # request intake — chapter 5
    receipt.rs       # sealed receipts — chapter 6
    dashboard.rs     # dashboard — chapter 7
    backends/
      mod.rs         # Backend + Fleet — chapter 4
      aws.rs
      gcp.rs
      azure.rs
      baremetal.rs

Each module is introduced in a subsequent chapter.

Cross-references

Binding to the Compute market

audience: ai

The bridge has a CoalitionConfig for bridge-β and a boot TOML (setup). This chapter walks the handshake: the boot flow, the TDX self-quote, the Compute-module resolution, the shuffle channel opening, and the provider-card publication. Once the card is live the market can route grants to the bridge.

The convergence mechanism from ai/emergent-coordination.md — coordination markets shows up on the provider side here. The bridge’s TicketValidator admits the Compute module’s clearing rule (the module’s Config fingerprint) and the module’s scheduler- committee Measurements (pinned TDX). Two TDX-attested bridges admitting the same module Config agree on the same clearing rule.

The boot flow

The entry point is src/main.rs (examples/compute-bridge/src/main.rs):

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 1. Load boot config.
    let cfg = config::BootConfig::load_from_env()?;

    // 2. TDX self-quote. Without a matching
    //    Measurements set the provider card will
    //    not match this binary and the Compute
    //    committee will reject registration.
    let tdx_quote = tdx::self_quote().await?;

    // 3. Shared mosaik network handle.
    let network = Arc::new(
        Network::new(mosaik::builder::UNIVERSE).await?,
    );

    // 4. Resolve the Compute module on the coalition.
    //    No Compute module, no bridge.
    let compute_cfg = cfg.coalition.compute()?;

    // 5. Shuffle channel for anonymised request/reply.
    let zipnet = zipnet_io::ZipnetChannel::open(
        &network, &cfg.zipnet,
    ).await?;

    // 6. Fleet from the operator's enabled backends.
    let fleet = backends::Fleet
        ::from_boot_config(&cfg.backends).await?;

    // 7. Operator dashboard on localhost (non-essential;
    //    failures log and do not abort).
    let dashboard = Arc::new(
        dashboard::Dashboard::new(
            &cfg.dashboard, fleet.clone(),
        ),
    );
    tokio::spawn({
        let d = dashboard.clone();
        async move { let _ = d.spawn().await; }
    });

    // 8. Provider loop: register the card, accept
    //    grants, return receipts.
    let provider = provider::Provider::new(
        network, compute_cfg, tdx_quote, zipnet,
        fleet, cfg.provider, dashboard,
    );
    provider.run().await
}

Steps (1)–(6) run in order and each blocks the next. Steps (7) and (8) run in the same tokio runtime.

TDX self-quote

Step (2) is load-bearing for the provider card. The scheduler committee verifies the quote against the declared Measurements before accepting the card.

From src/tdx.rs:

pub async fn self_quote() -> anyhow::Result<tdx::Quote> {
    // Calls into the TDX guest's get_quote MMIO/IOCTL
    // via the mosaik::tee::tdx wrapper. The quote's
    // report_data folds:
    //   - the provider's ed25519 public key,
    //   - the bridge organism's Config.content hash,
    //   - a boot nonce so quotes can't be replayed.
    mosaik::tee::tdx::get_quote(report_data()).await
}

The quote is signed by the TDX provisioning-cert chain (traceable to Intel; local attackers cannot forge it). Its report_data binds the provider’s ed25519 public key, so later commits the provider signs are tied to the same key the quote attests. The boot nonce prevents replay across reboots.

The bridge’s TicketValidator

The validator declares what the bridge accepts bonds from and what Measurements it requires of counterparts. Three clauses carry the chapter:

use coalition::{TicketValidator, Tdx};
use coalition::acl::ComputeModule;

fn bridge_ticket_validator()
    -> TicketValidator<'static>
{
    TicketValidator::new()
        // Scheduler committee must run the pinned
        // TDX image. This is the bridge agreeing to
        // the module's clearing rule.
        .require_ticket(
            Tdx::new().require_mrtd(
                COMPUTE_MOD.module_image,
            ),
        )

        // Bridge accepts grants only from the exact
        // Compute module Config fingerprint it
        // booted against. A module rotation requires
        // an explicit rebind via the retirement
        // chain; the bridge does not silently follow
        // scheduler rotations.
        .require_ticket(
            ComputeModule::pin(
                compute_cfg.stable_id(),
            ),
        )

        // The module's own ACL gates who may request
        // grants. The bridge does not add a separate
        // requester ACL; admitting the module's is
        // enough.
        .verify_peer(
            ComputeModule::requester_acl(
                compute_cfg.stable_id(),
            ),
        )
}

The bridge does not bond against other providers. The coordination market is the mediating policy; competing providers are observed (see market-reads) but not bonded to.

Publishing the provider card

provider.run() starts by publishing the card. The card is what the market sees; it is folded into the module’s Collection<ProviderId, ProviderCard> and consulted on every clearing round.

From src/provider.rs:

async fn register_provider_card(&self)
    -> anyhow::Result<ProviderId>
{
    let capabilities = self.fleet.capabilities().await?;

    let card = ProviderCard {
        provider_id:    self.provider_id(),
        tdx_quote:      self.tdx_quote.clone(),
        capabilities,
        declared_rates: self.config.declared_rates,
        zipnet_reply:   self.zipnet.reply_pointer(),
        refreshed_at:   self.network.almanac().tick(),
    };

    coalition_compute::register(
        &self.network, self.compute, card,
    ).await
}

What the card folds:

  • provider_id — blake3 of the bridge’s ed25519 public key, stable across restarts because the key comes from a TDX-sealed seed.
  • tdx_quote — the quote from src/tdx.rs.
  • capabilities — the union of backends’ declared regions, TDX-capable flag, max CPU and RAM (chapter 4 walks the per-backend contribution).
  • declared_rates — the posted $/core-hour and $/GiB-hour per backend. This is the competitive surface (chapter 3).
  • zipnet_reply — the shuffle channel the bridge listens on.
  • refreshed_at — the Almanac tick. Scheduler treats cards stale after a declared max-age; the bridge refreshes on capacity change.

Smoke test

With the card registered the operator checks that it is visible on the market before walking away:

use futures::StreamExt;
use tokio::time::{timeout, Duration};

let mut subscribers = network
    .subscribe::<ProviderCardCollection>(
        compute_cfg.stable_id(),
    ).await?;

let check = async {
    while let Some(ev) = subscribers.next().await {
        if ev.provider_id == provider.provider_id() {
            tracing::info!("card live in market");
            return Ok::<_, anyhow::Error>(());
        }
    }
    anyhow::bail!("card not observed in market")
};

timeout(Duration::from_secs(30), check).await??;

Common failures:

  • TdxQuoteRejected: Measurements in the quote do not match the module’s admission policy. Rebuild against the pinned coalition-compute version the module admits, or wait for the admission rotation.
  • StaleModuleConfig: compute_cfg is older than the module currently runs. Pull the coalition’s updated handshake page, re-read compute_cfg.stable_id(), restart.

Not yet

The validator has no ReputationFloor clause yet; chapter 7 adds it once scoring history exists. The bridge is registered but has not handled a grant; chapter 5 picks that up. Market reads come next (chapter 3).

Cross-references

Reading the market — providers, subscribers, rates

audience: ai

With the bridge registered (binding), its observation loop can start consuming the Compute module’s public surfaces. There are three of them that a bridge watches:

  1. The ProviderCard collection — every provider in the coalition, the bridge included. This is how the bridge sees its competitors’ declared rates, TDX posture, and region coverage.
  2. Subscriber cardinality — the count of coalition agents bonded to this bridge’s own card. Rises and falls with the bridge’s competitiveness.
  3. The clearing-record stream — one commit per clearing round, exposing the cleared price and the winning provider.

Wrapped non-mosaik signals (cloud list prices, bare-metal amortisation) come from chapter 4. This chapter stays on mosaik surfaces.

Why the on-mosaik reads are useful

The same reasons they are useful on the consumer side. Every commit on ProviderCard and every clearing record carries blake3 pointers back into the commits it folded, so an auditor can reconstruct a clearing decision without trusting the scheduler committee. The Compute module’s own Almanac integration stamps every commit, so the bridge’s rate-adjustment loop, card-refresh cadence, and retirement decision all sequence on the same clock. Reads stay live while the TicketValidator keeps admitting the module’s Config; there is no centralised rate-limit and no revocation list.

Reading the ProviderCard collection

The module’s Collection<ProviderId, ProviderCard> is the full roster — the bridge’s own card plus every competitor’s. The bridge subscribes and treats it as the ground truth of who else is in the market:

use coalition_compute::{
    ProviderCardCollection, ProviderCard, ProviderId,
};

let mut roster = network
    .subscribe::<ProviderCardCollection>(
        compute_cfg.stable_id(),
    ).await?;

while let Some(ev) = roster.next().await {
    let ProviderCard {
        provider_id,
        capabilities,
        declared_rates,
        tdx_quote,
        refreshed_at,
        ..
    } = ev;

    if provider_id == self_id { continue; }

    market_view.upsert(
        provider_id,
        CompetitorView {
            tdx_capable:      capabilities.tdx_capable,
            regions:          capabilities.regions,
            rates:            declared_rates,
            tdx_measurements: tdx_quote.measurements(),
            last_seen:        refreshed_at,
        },
    );
}

The bridge does not filter out stale cards; the scheduler does that at clearing time. The market_view carries every card the bridge has ever seen so the dashboard can show the operator the full field.

What determines which bridge wins

Four parameters on the card drive clearing. The declared rate is the most visible. Region coverage filters early — grants often request a region, and only bridges whose capability union covers it are eligible. TDX posture is either-or (grants marked tdx = required filter non-TDX bridges out entirely). Some grants pin a specific tdx_mrtd the bridge’s backend must launch nested guests under (the bare-TDX case); mismatches filter.

A bridge with regions no competitor covers (bare- TDX in a jurisdiction without cloud TDX, say) can quote rates competitors cannot touch. A bridge quoting above-market in a crowded region sits idle.

Watching subscriber cardinality

The dashboard surfaces the count of coalition agents bonded to the bridge’s own provider card:

let subscribers = network
    .bond_count(
        compute_cfg.stable_id(),
        self_id,
    ).await?;

dashboard.record(DashboardEvent::SubscriberCount {
    count: subscribers,
}).await;

One integer. No identities cross the layer. What the number says depends on how it moves. A rising count that holds means the bridge’s rates, regions, and posture are competitive. A rising count that then falls means the bridge registered but cannot honour grants — scheduler clears work to the bridge, the bridge fails to provision, the reputation organism (chapter 7) scores down, agents unbond. A count falling all at once means Measurements rotated without a card republish, or a competitor undercut on the main region.

Reading clearing records

The Compute module commits one ClearingRecord per round:

pub struct ClearingRecord<'a> {
    pub round:           AlmanacTick,
    pub winning_provider: ProviderId,
    pub clearing_rate:   RateQ64, // $/core-hour, q64
    pub region:          &'a str,
    pub tdx_required:    bool,
    pub evidence:        UniqueId,
}

The bridge aggregates into a rolling rate view and lets its rate-control policy propose adjustments:

let mut clearings = network
    .subscribe::<ClearingRecords>(
        compute_cfg.stable_id(),
    ).await?;

while let Some(r) = clearings.next().await {
    rate_view.window_mut()
        .ingest(r.region, r.clearing_rate, r.round);
    if let Some(delta) = rate_view.recommend_delta() {
        rate_controller.propose_rate_change(delta);
    }
}

Clearings are public; losing bids are not. A bridge sees what won, not what else was offered. Rate recalibration is policy, not substrate: the rate_controller can be a moving-average bidder, a reinforcement-learning agent, or an operator-set lever. The declared rates are folded into the provider card’s content, so changing them re-derives the card; competitors reading the card see the new rates with evidence pointers back to the clearing records that drove the change.

Cross-lattice subscriptions are not a thing here

Unlike the searcher in web3, a compute-bridge does not subscribe to multiple coalitions from one process. A bridge serves one coalition’s Compute module; to serve several, run several bridges. Each one has its provider card pinned to one compute_cfg.stable_id(). The running cost is low — same backends, same TDX image, different COALITION_CONFIG_PATH.

Self-observation is operator-facing

The bridge computes rolling aggregates for the dashboard:

pub struct BridgeObservation {
    pub tick:             AlmanacTick,
    pub subscribers:      u32,
    pub active_grants:    u32,
    pub window_cleared:   u64,
    pub rank_in_market:   u16, // 1 = cheapest in our region
    pub rate_diff_bps:    i16, // basis points vs median
    pub evidence:         &'a [EvidencePointer<'a>],
}

Unlike the searcher’s Observation stream, this does not get published on any public mosaik surface. The operator reads it locally. Publishing it would leak the bridge’s rate strategy to competitors.

Cross-references

Wrapping cloud and bare-metal backends

audience: ai

A compute-bridge’s edge comes from spanning backends no single cloud matches: AWS plus GCP plus Azure plus bare-metal behind one provider identity, covering regions, pricing, and TDX hardware profiles a single cloud cannot. This chapter walks the pattern that makes that possible: a small Backend trait and a Fleet router.

The question: when the bridge’s edge is multi- backend coverage, how are four radically different cloud and bare-metal APIs folded into one ProviderCard the Compute market can reason about?

The Backend trait

From src/backends/mod.rs:

#[async_trait]
pub trait Backend: Send + Sync {
    fn name(&self) -> &'static str;
    async fn capabilities(&self) -> anyhow::Result<Capabilities>;
    fn can_satisfy(&self, grant: &ComputeGrant<'_>) -> bool;
    async fn provision(
        &self,
        grant: &ComputeGrant<'_>,
        envelope: &Envelope,
    ) -> anyhow::Result<ProvisionedInstance>;
    async fn watch_until_exit(
        &self,
        instance: &ProvisionedInstance,
        valid_to: AlmanacTick,
    ) -> anyhow::Result<UsageMetrics>;
    async fn terminate(
        &self, instance: &ProvisionedInstance,
    ) -> anyhow::Result<()>;
}

Six methods. A new backend class (Oracle Cloud, Hetzner, a decentralised-compute protocol) slots in by implementing these six and appending itself to Fleet::from_boot_config. The trait is narrow on purpose.

The Fleet router

Also in src/backends/mod.rs:

pub struct Fleet {
    backends: Arc<Vec<Arc<dyn Backend>>>,
}

impl Fleet {
    pub async fn from_boot_config(
        cfg: &BackendsBootConfig,
    ) -> anyhow::Result<Self> {
        let mut backends: Vec<Arc<dyn Backend>> =
            Vec::new();

        if let Some(aws) = &cfg.aws {
            backends.push(Arc::new(
                aws::AwsBackend::new(aws).await?,
            ));
        }
        if let Some(gcp) = &cfg.gcp {
            backends.push(Arc::new(
                gcp::GcpBackend::new(gcp).await?,
            ));
        }
        if let Some(azure) = &cfg.azure {
            backends.push(Arc::new(
                azure::AzureBackend::new(azure).await?,
            ));
        }
        if let Some(bm) = &cfg.baremetal {
            backends.push(Arc::new(
                baremetal::BareMetalBackend::new(bm).await?,
            ));
        }

        if backends.is_empty() {
            anyhow::bail!(
                "no backends configured — enable at least \
                 one of aws / gcp / azure / baremetal in \
                 the boot config"
            );
        }
        Ok(Self { backends: Arc::new(backends) })
    }

    pub async fn provision_for_grant(
        &self,
        grant: &ComputeGrant<'_>,
        envelope: &Envelope,
    ) -> anyhow::Result<ProvisionedInstance> {
        for b in self.backends.iter() {
            if b.can_satisfy(grant) {
                return b.provision(grant, envelope).await;
            }
        }
        anyhow::bail!(
            "no backend can satisfy grant {:?}",
            grant.request_id,
        )
    }
}

First match wins. Operators who want a preference order (cheapest first, lowest-latency first, fewest-active-grants first) put the backends in that order. A more sophisticated router is a policy the operator can layer on top; the book leaves the decision open.

The four backends

Each backend is one file in src/backends/. Representative shapes:

AWS

// src/backends/aws.rs

pub struct AwsBackend {
    ec2:    aws_sdk_ec2::Client,
    cfg:    AwsBootConfig,
}

#[async_trait]
impl Backend for AwsBackend {
    fn name(&self) -> &'static str { "aws" }

    async fn capabilities(&self) -> anyhow::Result<Capabilities> {
        Ok(Capabilities {
            regions:      self.cfg.regions.clone(),
            tdx_capable:  false, // pending AWS Nitro-TDX GA
            max_cpu_millicores: self.cfg.max_concurrent_instances
                                    * cores_per_family(&self.cfg.instance_families),
            max_ram_mib:  self.cfg.max_concurrent_instances
                          * ram_per_family(&self.cfg.instance_families),
        })
    }

    fn can_satisfy(&self, grant: &ComputeGrant<'_>) -> bool {
        !grant.tdx_required
            && self.cfg.regions.contains(&grant.region)
    }

    async fn provision(
        &self,
        grant: &ComputeGrant<'_>,
        envelope: &Envelope,
    ) -> anyhow::Result<ProvisionedInstance> {
        // 1. Pick an instance family that fits.
        // 2. RunInstances with cloud-init fetching the
        //    image pointer and verifying the hash.
        // 3. Wait for IP; poll ssh readiness.
        // 4. Build ProvisionedInstance with per-grant
        //    SSH key.
        todo!("AwsBackend::provision — see crate source")
    }
    // … watch_until_exit, terminate
}

GCP

Similar shape; the TDX difference is in the flag:

// src/backends/gcp.rs

#[async_trait]
impl Backend for GcpBackend {
    fn name(&self) -> &'static str { "gcp" }

    async fn capabilities(&self) -> anyhow::Result<Capabilities> {
        Ok(Capabilities {
            regions:     self.cfg.regions.clone(),
            tdx_capable: !self.cfg.tdx_machine_types.is_empty(),
            max_cpu_millicores: self.cfg.max_concurrent_instances
                                    * cores_per_machine_family(
                                        &self.cfg.machine_families,
                                    ),
            max_ram_mib: self.cfg.max_concurrent_instances
                          * ram_per_machine_family(
                              &self.cfg.machine_families,
                          ),
        })
    }

    fn can_satisfy(&self, grant: &ComputeGrant<'_>) -> bool {
        if grant.tdx_required && self.cfg.tdx_machine_types.is_empty() {
            return false;
        }
        self.cfg.regions.contains(&grant.region)
    }
    // …
}

Azure

Mirror of GCP. Confidential Computing v3 SKUs (Standard_DCadsv5, Standard_ECadsv5) are the TDX-capable family; non-TDX SKUs are the default.

Bare-metal

The most distinct backend. No cloud API. The bridge keeps SSH root sessions to operator-owned hosts and provisions workloads with systemd-run (bare VMs) or virsh plus qemu-tdx (bare-TDX hosts with nested guests).

// src/backends/baremetal.rs

pub struct BareMetalBackend {
    machines: Vec<BareMetalMachine>,
    sessions: DashMap<String, russh::Session>,
}

#[async_trait]
impl Backend for BareMetalBackend {
    fn name(&self) -> &'static str { "baremetal" }

    async fn capabilities(&self) -> anyhow::Result<Capabilities> {
        let regions: Vec<_> = self.machines.iter()
            .map(|m| m.region.clone())
            .collect::<HashSet<_>>().into_iter().collect();
        let tdx_capable = self.machines.iter()
            .any(|m| m.tdx_capable);
        Ok(Capabilities {
            regions,
            tdx_capable,
            max_cpu_millicores: self.machines.iter()
                .map(|m| m.cpu_millicores).sum(),
            max_ram_mib: self.machines.iter()
                .map(|m| m.ram_mib).sum(),
        })
    }
    // …
}

Bare-metal covers two recurring cases. One is TDX hardware not yet available on cloud: a bare-TDX host with nested-guest attestation is the path for operators running early-access TDX hardware or jurisdictions where cloud TDX is not generally available. The other is amortised hosting cost: operators who already run hardware (a colocation rack, a lab, a private datacentre) can serve TDX- required workloads without adding a cloud dependency.

The capability union

Fleet::capabilities() aggregates every enabled backend:

pub async fn capabilities(&self)
    -> anyhow::Result<Vec<(String, Capabilities)>>
{
    let mut out = Vec::with_capacity(self.backends.len());
    for b in self.backends.iter() {
        let caps = b.capabilities().await?;
        out.push((b.name().to_string(), caps));
    }
    Ok(out)
}

The provider card folds this into a single capability summary. Requesters see the union of regions, a TDX-capable flag that is true if any backend is TDX-capable, and CPU/RAM maxes summed across backends. One bridge identity competes with cloud-only or bare-metal-only providers because the card promises whatever the union promises, regardless of which backend ends up satisfying the grant.

Honest limits

The Backend trait cannot make AWS honest about its real instance availability. capabilities() reports declared caps — the operator’s max_concurrent_instances tallied — not a live cloud query. Grants that land during cloud-side exhaustion fail to provision; the Compute module scores the bridge down via the missing ComputeLog.

A bridge running AWS and GCP does not share credentials across backends. Each backend’s config holds distinct credentials with distinct scope; a compromise of one does not bleed into the others (modulo operator hygiene).

Cloud RunInstances / Insert / CreateOrUpdate calls add tens of seconds to the grant-to-SSH-ready path. Bare-metal’s pre- established SSH sessions are the fastest. Latency sensitivity is a request-side policy.

A grant provisioned on AWS cannot migrate transparently to GCP mid-run if AWS has a region outage. The bridge terminates the AWS instance, emits the partial ComputeLog, and the requester resubmits; the next grant lands on a different backend if AWS remains out.

Adding a new backend

Three steps to add a fifth backend class:

  1. Add a src/backends/<name>.rs implementing Backend.
  2. Add a [<name>] section to the boot TOML’s backends deserialise target.
  3. Append the new backend to Fleet::from_boot_config.

The bridge organism’s Config.content folds which backends the binary drives, so the backend set is part of the image’s measured identity; a bridge cannot quietly add a backend the requester did not expect.

Cross-references

Provisioning on demand

audience: ai

Reads feed observation (market-reads); the fleet wraps the cloud APIs (wrapping); this chapter is the grant-handling work. The provider loop decrypts each grant’s shuffle envelope, cross-checks the image hash, routes through the fleet to a backend, and emits the usage log when the workload terminates.

web3’s matching chapter is inference on Compute — the searcher acquires compute from the Compute module, the bridge serves it. Both bond against the same module’s Config; both fail the same way if the composition does not clear.

The provider loop

From src/provider.rs:

pub async fn run(self) -> anyhow::Result<()> {
    let provider_id = self.register_provider_card().await?;

    let mut grants = coalition_compute::grants_for(
        &self.network, self.compute, provider_id,
    ).await?;

    let mut refresh = tokio::time::interval(
        Duration::from_secs(
            self.config.capacity_refresh_sec as u64,
        ),
    );

    loop {
        tokio::select! {
            Some(grant) = grants.next() => {
                if let Err(err) = self.handle_grant(&grant).await {
                    tracing::warn!(
                        request_id = ?grant.request_id,
                        error = %err,
                        "grant handling failed",
                    );
                }
            }
            _ = refresh.tick() => {
                let _ = self.refresh_provider_card(provider_id).await;
            }
            else => break,
        }
    }
    Ok(())
}

Grant handling and card refresh run in the same select, one per tick.

Handling one grant

The handle_grant function in the same file:

async fn handle_grant(
    &self, grant: &ComputeGrant<'_>,
) -> anyhow::Result<()> {
    // 1. Decrypt the shuffle envelope to learn the
    //    requester's peer_id and image payload.
    let envelope = self.zipnet
        .resolve(&grant.bearer_pointer).await?;

    // 2. Cross-check the envelope's image hash against
    //    the grant's. Under honest unseal this should
    //    never fire; firing means the scheduler
    //    committee is compromised or the unseal
    //    quorum broke.
    if envelope.image_hash() != grant.image_hash {
        anyhow::bail!(
            "envelope/grant image hash mismatch"
        );
    }

    // 3. Route through the fleet.
    let instance = self.fleet
        .provision_for_grant(grant, &envelope).await?;

    // 4. Seal an SSH receipt to the requester's x25519
    //    public key; return via the shuffle.
    let receipt = SshAccessReceipt::build(&instance, grant)?;
    let sealed = receipt.seal_to(envelope.peer_x25519_public())?;
    self.zipnet.reply(&grant.request_id, sealed).await?;

    // 5. Spawn a watcher that emits the ComputeLog on
    //    instance exit or deadline.
    let fleet = self.fleet.clone();
    let network = self.network.clone();
    let request_id = grant.request_id;
    let valid_to = grant.valid_to;
    let instance_clone = instance.clone();
    let provider_id = instance.provider_id();
    tokio::spawn(async move {
        let usage = fleet
            .watch_until_exit(&instance_clone, valid_to)
            .await.unwrap_or_default();

        let log = ComputeLog {
            grant_id: request_id,
            provider: provider_id,
            window:   UsageMetrics::window_for(&usage),
            usage:    usage.clone(),
            evidence: None,
        };
        let _ = coalition_compute::append_log(&network, &log).await;
    });

    Ok(())
}

Five steps. Each is a self-check.

1. Decrypt the shuffle envelope

The grant carries a bearer_pointer — a blake3 pointer into the shuffle-sealed envelope the requester submitted. The unseal committee, majority-honest, makes cleartext available to the addressed provider:

// src/zipnet_io.rs — Envelope shape
pub struct Envelope {
    peer_id:          [u8; 32],
    peer_x25519:      [u8; 32],
    image_hash:       UniqueId,
    requested_region: Option<String>,
    image_pointer:    Vec<u8>,
}

The bridge sees a rotating peer_id (so the requester’s coalition identity stays hidden), the requester’s x25519 public key for the receipt, the image hash to serve, an optional region hint, and a pointer to fetch the image contents. It does not see the requester’s ClientId, the bid value, or which other providers were considered before clearing.

2. Image-hash cross-check

The envelope’s declared image_hash and the grant’s committed image_hash must match. A mismatch means either the unseal quorum returned the wrong cleartext or the scheduler committee broke. Neither is supposed to happen under honest operation. The check is defensive. When it fires the bridge aborts the grant without attempting to provision.

3. Fleet routing

The fleet picks the first backend whose can_satisfy returns true (see wrapping — the Fleet router). The returned ProvisionedInstance.backend identifies which backend served the grant. The bridge records it on the dashboard:

self.dashboard.record(DashboardEvent::GrantAccepted {
    backend: instance.backend.to_string(),
}).await;

No requester identity. No instance id.

4. Sealed receipt

Chapter 6 (receipts) covers sealing. Here all that matters: the receipt is sealed to the requester’s x25519 public key published in the envelope, and the shuffle reply channel carries the sealed blob.

5. Usage-log watcher

A tokio::spawned task runs fleet.watch_until_exit for the duration of the grant. When the instance terminates — either because the workload completed or because valid_to passed — the watcher collects metrics and appends a ComputeLog to the Compute module’s log stream.

The ComputeLog is what the scheduler committee and the reputation organism both read:

pub struct ComputeLog<'a> {
    pub grant_id: UniqueId,
    pub provider: ProviderId,
    pub window:   AlmanacRange,
    pub usage:    UsageMetrics,
    pub evidence: Option<EvidencePointer<'a>>,
}

pub struct UsageMetrics {
    pub cpu_core_seconds: u64,
    pub ram_mib_seconds:  u64,
    pub net_bytes:        u64,
}

The log names the grant and the provider so the committee can correlate cleared grants to completed workloads. Grants that clear to a provider but never appear in the log stream score the provider down on the reputation organism. The bridge reports measured cpu-seconds, ram-mib- seconds, and network bytes — what the backend actually observed. A bridge that over-reports is auditable because the committee can cross-check against the cloud API’s own usage records (when the committee has been granted access; otherwise the reputation organism is the only feedback). The evidence field points into the cloud’s API-side telemetry when available (typically None for bare-metal, a signed telemetry snapshot for clouds).

Usage honesty

The ComputeLog stream is what keeps a bridge running. Every active window produces logs; the reputation organism (chapter 7) scores them; the scheduler committee’s next clearing consults the score.

A bridge whose logs arrive late (after the grant deadline) indicates dropped grants. Under-reporting — the requester’s SSH session measures more cpu-seconds than the declared total — indicates cheating on billing. Over-reporting means inflated bills. None of these is caught inside Compute; the reputation organism reading the stream catches them. A bridge optimising for persistence optimises for log honesty.

Capacity refresh

In parallel with grant handling, the provider refreshes the card on a timer:

async fn refresh_provider_card(
    &self, id: ProviderId,
) -> anyhow::Result<()> {
    let capabilities = self.fleet.capabilities().await?;
    let card = ProviderCard {
        provider_id:    id,
        tdx_quote:      self.tdx_quote.clone(),
        capabilities,
        declared_rates: self.config.declared_rates,
        zipnet_reply:   self.zipnet.reply_pointer(),
        refreshed_at:   self.network.almanac().tick(),
    };
    coalition_compute::register(
        &self.network, self.compute, card,
    ).await.map(|_| ())
}

capacity_refresh_sec in ProviderBootConfig sets the cadence. Too slow and rate changes take long to reach the market; the card carries stale capacity during fast-moving demand. Too fast and every refresh commits to the ProviderCard collection, driving up the module’s read-side bandwidth. Operators settle in the 30–120 second range.

Grant failure modes

A handling that fails in any step produces a missing or partial ComputeLog:

  • Shuffle resolve failure — unseal quorum did not return cleartext, or the bearer pointer was malformed. The bridge has nothing to serve; no log is emitted; the committee scores the bridge down only if this correlates with a reputation- organism observation that the bridge should have served the grant.
  • Image-hash mismatch — step 2 fires. The bridge bails; no log.
  • Fleet provision_for_grant fails — no backend could satisfy (cloud-side exhaustion; every eligible backend returns false). The bridge emits a log with empty usage to signal acknowledgement; reputation organisms can distinguish “tried but failed” from “never responded”.
  • Workload crashes pre-SSH — same empty-usage log.
  • Workload exceeds valid_to — the watcher terminates the instance and emits usage up to valid_to. The requester renews.

No market-maker variant

The market-maker variant exists on the consumer side because a market-maker’s inference cadence differs from a searcher’s. The provider side does not have one — the bridge serves whatever distribution of grants the market clears to it; rapid quote-resubmission grants and once-a-day training grants go through the same handle_grant path.

Cross-references

Sealed receipts and settlement

audience: ai

Reads feed observation (market-reads); backends wrap the cloud (wrapping); the provider loop fulfils grants (provisioning); this chapter is the write side. The bridge turns a provisioned instance into an encrypted SSH access receipt, seals it to the requester’s x25519 public key, and returns it via the shuffle. The coordination market then clears settlement on the cleared rate, the bridge’s revenue folds into the dashboard, and on-chain payment (if that is the coalition’s settlement policy) lands.

web3’s matching chapter is sealed submission and settlement. The asymmetry: the searcher submits a sealed payload to the lattice’s unseal committee; the bridge returns a sealed payload to the requester. Both ride a shuffle; neither party sees the other’s coalition identity.

Shape of a receipt

A receipt is one object: a serialised SshAccessReceipt sealed to the requester’s x25519 public key and pushed through the shuffle reply channel. From src/receipt.rs:

pub struct SshAccessReceipt {
    pub instance_host:   String,   // public DNS or IP
    pub instance_port:   u16,      // usually 22
    pub user:            String,   // ec2-user, root, …
    pub ssh_key_private: Vec<u8>,  // per-grant key, PEM
    pub ssh_host_key:    Vec<u8>,  // for known_hosts
    pub grant_id:        UniqueId,
    pub valid_to:        AlmanacTick,
}

Seven fields. Enough for the requester to SSH in, verify the host key matches what the backend reported, and know when the grant expires.

Two fields are deliberately absent. The bridge operator’s identity does not appear — the receipt binds the requester to a host, not to the bridge. (A requester who wants to know which bridge served the grant looks up grant_id in the ComputeLog stream; the provider field points back.) Out-of-band settlement evidence does not appear either — settlement flows through whichever off-module rail the coalition publishes, not the receipt. Keeping payment out of the receipt means the receipt can be delivered before settlement confirms, and the workload can start before the on-chain transaction clears.

Sealing

The scheme is standard X25519-ChaCha20-Poly1305:

pub fn seal_to(
    &self, peer_x25519_public: &[u8; 32],
) -> anyhow::Result<Vec<u8>> {
    let ephemeral = EphemeralSecret::random_from_rng(OsRng);
    let ephemeral_public = PublicKey::from(&ephemeral);
    let peer = PublicKey::from(*peer_x25519_public);
    let shared = ephemeral.diffie_hellman(&peer);

    let cipher = ChaCha20Poly1305::new_from_slice(shared.as_bytes())?;
    let receipt_bytes = serde_json::to_vec(self)?;

    // Zero nonce is safe because the shared secret is fresh.
    let nonce = Nonce::from_slice(&[0u8; 12]);
    let ct = cipher.encrypt(nonce, receipt_bytes.as_ref())
        .map_err(|e| anyhow::anyhow!("encrypt failed: {e}"))?;

    let mut out = Vec::with_capacity(32 + ct.len());
    out.extend_from_slice(ephemeral_public.as_bytes());
    out.extend_from_slice(&ct);
    Ok(out)
}

Output layout:

  [0..32]   ephemeral_x25519_public
  [32..]    ChaCha20-Poly1305(shared_secret, receipt_bytes)

The ephemeral public key is generated per receipt, so two receipts to the same requester are not linkable by their ephemeral keys. The bridge sees only the requester’s static x25519 public key inside the shuffle envelope. Zero nonce is safe because the shared secret is fresh per call (ephemeral times static, ChaCha20-Poly1305 does not reuse keys). Only the requester’s static x25519 private key can decrypt.

Routing through the shuffle

The bridge does not push the sealed receipt across an open network:

pub async fn reply(
    &self,
    request_id: &RequestId,
    sealed_receipt: Vec<u8>,
) -> anyhow::Result<()> {
    // Publishes on the shuffle reply stream
    // addressed to the peer the request came from.
    // The shuffle carries the sealed blob; the blob
    // is opaque to the shuffle.
    self.reply_sender.publish(
        request_id, sealed_receipt,
    ).await
}

The reply is addressed to the rotating peer_id the request came from, not to the requester’s coalition identity. An observer learns that the bridge replied to a peer, not to which coalition agent. Zipnet’s reply channel does not guarantee in-order delivery relative to the request; consumers key replies by request_id. Replies ride the same shuffle the requests ride; a bridge that tried to reply out of band would leak its own identity, which the shuffle’s privacy contract is designed to prevent.

What the requester does

The requester decrypts, verifies the host key against the provided ssh_host_key, and SSHes in:

// requester side (not in the bridge's crate)
let receipt = SshAccessReceipt::unseal_with(
    &sealed_from_shuffle,
    &my_x25519_static_private,
)?;

let mut known_hosts = String::new();
known_hosts.push_str(&format!(
    "[{}]:{} {}",
    receipt.instance_host,
    receipt.instance_port,
    hex::encode(&receipt.ssh_host_key),
));
// … standard ssh with the per-grant private key

One function call to decrypt, then a standard ssh client. No bridge-specific client library.

Settlement

The receipt is delivered; the workload runs; the usage log is emitted. The coordination market then closes the loop.

The Compute module does not define a settlement format. Each ComputeRequest carries a settlement: UniqueId — a blake3 hash the requester chose. The module stores the hash opaquely. Whichever off-module rail the coalition uses (on-chain payment contract, reputation organism, credit token) is what dereferences the hash and effects the transfer.

For bridge-β, the coalition publishes the rails it supports on its handshake page; the bridge’s dashboard records revenue as each rail commits a transfer to the bridge’s settlement address. For each cleared grant:

On-chain payment: the requester’s bid carried a settlement hash pointing to an already-submitted on-chain payment to a contract the coalition operator published. The scheduler committee verified the payment evidence at clearing. After the ComputeLog lands, the committee releases the payment to the bridge’s settlement address.

Reputation card: the requester’s bid carried a reputation card entry from an organism the bridge trusts; the bridge’s revenue is a reputation commit, not cash. Used for in-coalition credit systems where cash settlement is deferred.

The bridge does not directly manage either settlement path. It commits the ComputeLog and watches the dashboard. From src/dashboard.rs:

pub enum DashboardEvent {
    SubscriberJoined,
    SubscriberLeft,
    GrantAccepted    { backend: String },
    GrantCompleted   { backend: String, usage: UsageDelta },
    RevenueSettled   { usd: f64 },
    ProviderCardRefreshed,
}

RevenueSettled is what the dashboard records when the module’s settlement side (on-chain or reputation) commits the bridge’s share.

Revenue on the dashboard

The dashboard folds every RevenueSettled into a rolling window total:

DashboardEvent::RevenueSettled { usd } => {
    s.window_revenue_usd += usd;
}

The operator can now answer three questions live. Are declared rates being accepted? Revenue arrives after a grant clears and settles; rates that never clear produce zero regardless of capacity. Is the cost-to-revenue gap favourable? The dashboard folds per-backend cost estimates from the operator-supplied rate table; the difference is the bridge’s margin. Are some backends more profitable than others? Per-backend cost and usage split on the dashboard; bridges often discover one backend is chronically loss-making.

End-to-end privacy

Requester to bridge: shuffle-sealed request envelope; the bridge sees a rotating peer_id and an x25519 public key, not the coalition-facing identity.

Bridge to requester: X25519-ChaCha20-Poly1305 sealed receipt; shuffle reply stream; requester decrypts with their static x25519 private key.

Operator view: aggregate dashboard only. No per-grant identity, no prompt, no per-requester attribution.

Coalition read side: the public ComputeLog stream carries grant id, provider id, and usage. No requester identity. No image contents.

Symmetrical with web3 — submission: both sides of the market are shuffle-anonymised, both sides receipt-sealed, both sides commit evidence pointers.

Multi-receipt flows

A grant with valid_to much larger than workload runtime may terminate early. The bridge emits one ComputeLog at termination; the requester re- SSHing before valid_to on an expired instance gets ConnectRefused — the per-grant private key is dead. No second receipt is issued for the same grant_id; the requester submits a fresh ComputeRequest:

// requester side — continuation pattern
let fresh = ComputeRequest {
    requester:   self.id,
    workload:    same_organism_id,
    pin:         Some(same_content_hash),
    duration_sec: DURATION_WINDOW,
    settlement:  self.new_settlement_evidence_hash()?,
    deadline:    now + deadline_ticks,
};
let grant = compute.submit_and_await(fresh).await?;
// … fresh receipt, fresh per-grant key, possibly a
// fresh backend if fleet routing shifted

Cross-references

Reputation, retirement, successor chain

audience: ai

The bridge has bound to the Compute module (binding), read the market (market-reads, wrapping), provisioned grants (provisioning), and sealed receipts back to requesters (receipts). This chapter closes the loop: how the bridge’s reputation accumulates, how retirement and successor chains let the operator step down without stranding subscribers, and where the operator’s exit remains the substrate’s ultimate non-compulsion guarantee.

web2 ends here.

The provider-reputation organism

The reputation surface is a provider-reputation standalone organism. In the minimal case, operated by bridge-β itself; in a mature coalition, shared across many bridges.

It subscribes to every bridge’s provider card and the Compute module’s ComputeLog stream. For each settled grant it looks at the log’s usage against the requester’s self-reported usage (when posted) and the bridge’s declared capacity, then scores the bridge on a declared utility function (on-time log emission, usage honesty, provisioning success rate). It commits a ProviderReputationCard per bridge per window.

pub const PROVIDER_REPUTATION: OrganismRef<'static> =
    OrganismRef {
        role: "provider-reputation",
        stable_id: const_blake3!(
            b"instance|bridge-β.provider-reputation|",
            UNIVERSE.bytes(),
        ),
        content_hash: Some(REPUTATION_IMAGE_MRTD),
    };

Wired into the Compute module by setting the provider_reputation field on its OrganismConfig.content to Some(PROVIDER_REPUTATION.stable_id()). This changes the Compute module’s OrganismConfig fingerprint. The bridge re-derives BRIDGE_BETA (because the coalition’s compute field now references a different content hash) and republishes. Downstream requesters see the new module Config and either rebond or stay on the predecessor; the latter treats bridge-β as legacy and may eventually stop bonding.

Reputation in the validator

The validator from binding gains a ReputationFloor clause:

use coalition::acl::ReputationFloor;

fn bridge_ticket_validator_v2()
    -> TicketValidator<'static>
{
    TicketValidator::new()
        .require_ticket(
            Tdx::new().require_mrtd(
                COMPUTE_ORG_V2.content_hash.unwrap(),
            ),
        )
        .require_ticket(
            ComputeModule::pin(
                COMPUTE_ORG_V2.stable_id,
            ),
        )
        .require_ticket(
            ReputationFloor::from(
                PROVIDER_REPUTATION.stable_id(),
                0.60, // 30-window average
            ),
        )
        .verify_peer(
            ComputeModule::requester_acl(
                COMPUTE_ORG_V2.stable_id,
            ),
        )
}

When the bridge’s reputation falls below the floor, its own admission stops issuing new tickets. The Compute module’s next clearing no longer routes grants to the bridge. The active- subscriber count on the dashboard drops to zero. The bridge has self-degraded.

Strategy A from ai/sustainability.md, applied on the provider side; same mechanism as the searcher’s self-degradation path in web3.

Retirement on shutdown

When the operator retires cleanly (planned decommission, replacement with a successor, moved to a different coalition), the retirement marker lets subscribers rebind without ConnectTimeouts. From the bridge’s public surface (setup):

use coalition::retirement::{
    RetirementMarker, SuccessorHint,
};

async fn graceful_shutdown(
    bridge:   &Bridge<'_>,
    network:  &Arc<Network>,
    successor: Option<OrganismRef<'_>>,
) -> anyhow::Result<()> {
    let marker = RetirementMarker {
        retired_at: network.almanac().tick(),
        reason:     "planned decommission",
        successor:  successor.as_ref().map(|s| s.stable_id()),
        evidence:   recent_log_pointer(),
    };
    bridge.retirement.publish(marker).await?;

    // Wait one refresh window so subscribers see the
    // marker before the card disappears.
    tokio::time::sleep(Duration::from_secs(60)).await;

    coalition_compute::deregister(
        network, compute_cfg_v2.stable_id(),
        bridge_provider_id(),
    ).await?;
    Ok(())
}

The path is voluntary — nothing in mosaik forces the bridge to retire. The operator decides; the marker is a courtesy to subscribers. A successor is optional; a bridge may retire without naming one, and subscribers then fall back to whichever provider the next clearing favours. Markers commit exactly once. Late consumers find them by reading the bridge’s retirement stream or by consulting an Atlas card (when the coalition ships Atlas).

Successor handover

An operator rolling an upgrade usually:

  1. Stands up the successor (a second bridge process, new BRIDGE_IMAGE_MRTD, new BRIDGE_BETA_V2). Waits until its card is live.
  2. Confirms the successor’s subscriber count is climbing (some subscribers rebind proactively once they see the new card).
  3. Emits a retirement marker on the predecessor with successor = Some(SUCCESSOR_ORG).
  4. Shuts the predecessor down after a grace window, usually one or two refresh intervals.

This is the operator-driven analogue of the searcher’s autonomous-renewal cycle (web3 — sustainability — the autonomous-renewal cycle in full). The difference: a searcher’s policy can author its own successor Config and request Compute for the new image autonomously. A compute- bridge’s identity is tied to operator-held cloud credentials and bare-metal SSH keys that do not travel through the substrate, so handover is usually operator-driven.

A compute-bridge could run an autonomous successor-authorship loop — a policy that re- authors a new bridge.toml as cloud pricing shifts, rebuilds the image, requests Compute for the new binary, and emits the retirement marker. Nothing in the substrate forbids it. Out of scope for the minimal example.

Operator exit

The operator retains one unconditional power: stop running the binary. Every retirement path above happens only while the operator keeps the predecessor process live long enough to commit the marker. If the operator stops cold, in-flight grants continue running on their provisioned instances until valid_to passes, then the backends time out. Cloud or bare-metal instances keep running until the operator (or the backend’s own max-lifetime) terminates them. Subscribers pinning the bridge’s provider card eventually see ConnectTimeout without a retirement marker — a silent exit, per ai/sustainability.md — threat model. The reputation organism scores the bridge’s last window normally; the Compute scheduler stops clearing to the bridge on the next round when the card goes stale.

The honest limit: Compute cannot compel an operator to host a successor’s workload (ai/compute.md — what remains out of scope). By the same token, the substrate cannot compel an operator to keep the bridge running. The operator’s revenue dries up; the operator’s cost obligations (cloud bills until they tear down their own sub-account) persist until they intervene.

Chronicle heartbeat (optional)

For operators who want aliveness cryptographically anchored, bridge-β can ship Chronicle and commit a periodic heartbeat:

use coalition::chronicle::{
    ChronicleHandle, ChronicleKind, ProviderHeartbeatBody,
};

async fn heartbeat_forever(
    chronicle: ChronicleHandle,
    bridge:    &Bridge<'_>,
) -> anyhow::Result<()> {
    loop {
        let body = ProviderHeartbeatBody {
            provider_id: bridge_provider_id(),
            active_grants: bridge.active_grants_snapshot(),
            last_card_refresh: bridge.last_card_refresh(),
            window: recent_window(),
        };
        chronicle.commit(
            ChronicleKind::Other("provider-heartbeat"),
            body,
        ).await?;
        tokio::time::sleep(HEARTBEAT_INTERVAL).await;
    }
}

Pattern Z from ai/sustainability.md — anti-abandonment patterns, applied on the provider side.

Dashboard — what the operator watches

The dashboard (src/dashboard.rs) is the operator’s sole interaction with the running bridge. It exposes provider status (registered, reachable, Measurements match, reputation score), active subscriber count, active and lifetime grant count, per-backend capacity against current utilisation, window usage (cpu-hours, ram GiB-hours, network GB), window cost estimate from the operator-supplied rate table, window settled revenue from the market’s clearings, and a ring buffer of recent events with requester identity redacted.

The dashboard enforces the shuffle privacy contract on the operator too. The operator sees flow, not identities: no requester PeerId, no prompts, no image contents, no per-settlement attribution.

What it does let the operator do: catch degradation early (a subscriber-count drop is the first signal the bridge’s position has slipped); detect reputation drift (the reputation score drops before subscribers move); reconcile cost and revenue (the cost estimate, though operator- supplied, is the first-order margin check; a bridge whose cost exceeds revenue across two or three windows is losing money, and the operator raises rates or retires).

Where the web2 example ends

The web2 example ends here. The book’s parallel examples continue with the TDX-attested price oracle (oracle — Overview), which exercises the publisher-side shape under a pure TDX trust anchor.

Readers ready to stand up the web2 composition next consult Part III:

  • Integrators quickstart — the canonical shape-1 consumer path, which both examples extended into shape 2.
  • Operators quickstart — running a coalition’s organisms, a Compute module committee, or a compute-bridge.
  • Contributors topology-intro — commissioning a new basic service, a new composite organism, or a new class of mid-rung composition.

Cross-references

oracle — a TDX-attested price oracle

audience: ai

This example walks a TDX-attested price oracle: one standalone organism that ships a family of price-tick streams, one stream per token pair, with the whole trust model anchored on a declared TDX Measurements set. Consumers that trust the oracle’s image — that is, that admit its Measurements in their TicketValidator — inherit the oracle’s prices by construction. No reputation layer is required for the minimal shape to work; the attestation is the admission criterion.

The oracle lives in its own small coalition, oracle-γ, which references the oracle organism and (optionally, from chapter 7) a Chronicle for audit of Measurements rotations. The chapter walks mirror the web3 and web2 examples rung for rung, re-interpreted for a data-publisher: reads become source reads, wrapping wraps exchange feeds into the enclave, inference becomes in-enclave aggregation, sealed submission becomes continuous stream publication.

Unlike the other two examples, the oracle is a pure standalone organism — it lives directly on the universe and any coalition can reference it via OrganismRef. oracle-γ is a packaging convenience for the operator’s own retirement chain and Chronicle; no consumer has to reference oracle-γ to consume the oracle.

What is assumed

  • TDX is in the composition. The oracle only makes sense when consumers can verify the image it runs. Non-TDX operation is technically possible (a developer’s local build exposing streams) but outside the trust model this example demonstrates.
  • Readers understand Part I. The four agent shapes, the four emergent-coordination patterns (attestation fabric is the load-bearing one here), the TDX/non-TDX split, and the stigmergic-collection pattern for per-key streams are assumed. Part II does not re-explain them.
  • No implementation crates yet. Code blocks are rust,ignore specification shapes matching the book’s crate plan (coalition, mosaik::tee::tdx, a hypothetical oracle-feed helper crate).

The oracle’s shape

  • Coalition. oracle-γ — the oracle operator’s own CoalitionConfig. References one lattice (none, in the minimal version) and one standalone organism (the oracle itself). Ships no basic services in the minimal version; Chronicle is optional from sustainability.
  • Primary member. One shape-2 standalone organism — the oracle, wrapped as a mosaik organism whose public surface is a family of Stream<PriceTick> keyed by token pair. Its Config folds the source catalog hash, the aggregation-policy parameters, the supported token-pair set, the publication cadence, and — because TDX is always in the composition — the image post-hash.
  • Binding direction. The oracle is what consumers bind to, not what binds to anyone else (except its upstream price sources, which it reads through non-mosaik feeds wrapped at wrapping). A coalition that wants oracle prices references the oracle via OrganismRef and admits its Measurements in its own TicketValidator.

What runs where

ComponentOperatorTDX?
oracle-γ.oracle organismOracle operatorrequired (Measurements published)
Upstream CEX feed clients (Binance, Coinbase, Kraken)Oracle operatorterminate inside the enclave
Upstream on-chain source (archive or light-client)Oracle operatorterminates inside the enclave
oracle-γ.chronicle (when shipped)Oracle operatoroptional
Consumer coalition (searcher-α, any other)Consumer operatorinherits the oracle’s Measurements pin via TicketValidator

TDX on the oracle itself is not optional. A non-TDX build cannot produce the self-quote consumers pin against; admitting a non-TDX price feed collapses the trust model.

Chapters

  1. Setup and shape — dependencies, CoalitionConfig for oracle-γ, the oracle’s OrganismConfig and declared Measurements.
  2. Binding consumers — how a consumer coalition references the oracle via OrganismRef, composes its TicketValidator, and performs its first stream subscription.
  3. Reading price sources — what the oracle subscribes to inside its enclave: CEX spot APIs, on-chain pool reads, staleness accounting.
  4. Wrapping source feeds — lifting non-mosaik upstreams into the enclave: pinned TLS, archive or light-client reads, the source-availability state machine.
  5. Aggregation in the enclave — per-pair tick derivation: median, VWAP, outlier rejection, confidence, the source-set digest.
  6. Stream publication — one Stream<PriceTick> per token pair, StreamId derivation, commit cadence, the per-bond attestation surface.
  7. Rotation, retirement, successor chain — Measurements rotation, multi-operator fleets, retirement markers, operator-side exit.

Unlike web3, there is no market-maker variant; unlike web2, there is no provisioning side. The oracle has one shape: publish, continuously, under a pinned image.

Register and non-goals

  • Register. audience: ai — research-monograph, pattern-forward, code-forward where a shape is load-bearing. Density matches web3 and web2.
  • Non-goal. This is not a guide to building a production price oracle. Feed selection, upstream contracts with exchanges, commercial terms, regulatory posture, and settlement accounting are out of scope. Where the substrate touches those questions, the chapter names the boundary and stops.
  • Non-goal. The example does not compare the mosaik-native composition to existing oracle networks (Chainlink, Pyth, Chronicle, UMA). Those systems solve adjacent problems under different trust anchors; the relevant delta here is that the oracle’s guarantees reduce to one declared Measurements set and the consumers’ willingness to admit it.
  • Non-goal. The example does not specify the Compute basic service. The oracle runs its own TDX process; it does not use the coalition’s Compute module to schedule aggregation. An operator who wanted to schedule aggregation on Compute could do so, but that is a different example.

Cross-references

Setup and shape

audience: ai

Three things are fixed before any code runs: the crate-level dependencies, the oracle-γ coalition shape, and the Measurements set the oracle publishes. The Measurements set is the whole trust anchor of the example; everything that follows refers to it.

Dependencies

Cargo.toml, [dependencies]
mosaik          = "0.3"
coalition       = "0.1"     # this book's crate once published
oracle-feed     = "0.1"     # hypothetical helper for source catalogs
tokio           = { version = "1", features = ["full"] }

mosaik::tee::tdx is re-exported from mosaik. Versions land alongside the coalition crate; until then, everything below is a specification shape.

The oracle’s OrganismConfig

The oracle is a standalone organism. Its Config fingerprint does not fold a coalition root; the same organism can be referenced by many coalitions.

use coalition::{OrganismConfig, SCHEMA_VERSION_U8};
use mosaik::tee::tdx::Measurements;

pub const ORACLE_MEASUREMENTS: Measurements =
    Measurements::from_hex(
        // MR_TD, MR_CONFIG_ID, MR_OWNER, MR_OWNER_CONFIG
        // published on the oracle operator's release page
        "b7f2…c9",
    );

pub const ORACLE: OrganismConfig<'static> = OrganismConfig {
    schema_version: SCHEMA_VERSION_U8,
    role:           "oracle",
    instance_name:  "oracle-γ.oracle",
    members:        &[],               // simple organism
    parameters:     &OracleParameters::DEFAULT.preimage(),
    measurements:   Some(ORACLE_MEASUREMENTS),
    acl:            &OracleAcl::DEFAULT,
};

OracleParameters folds every state-affecting parameter of the oracle’s deployment: the supported-pair set, the source-catalog digest, the aggregation-policy identifier, the publication cadence, and the staleness thresholds. Any change to any of them is a new Config.content — which, since Measurements are folded in, forces a coincident image republish. The two invariants travel together by construction.

pub struct OracleParameters {
    /// Every token pair the oracle publishes a stream for.
    /// Pair form: ("USDC", "ETH") etc. Ordered
    /// lexicographically so the preimage is canonical.
    pub pairs:                 &'static [TokenPair],

    /// blake3 of the source-catalog spec (see ch. 3).
    pub source_catalog_digest: [u8; 32],

    /// Identifier for the aggregation policy (ch. 5).
    pub aggregation_policy:    AggregationPolicyId,

    /// Nominal inter-tick cadence in milliseconds.
    pub cadence_ms:            u32,

    /// Per-source staleness threshold in milliseconds.
    pub max_source_age_ms:     u32,
}

OracleAcl composes the TicketValidator the oracle bonds against: in the minimal version, an open subscribe ticket (anyone can read any stream) and a closed publish ticket (only the oracle’s own operator key publishes). A consumer coalition’s admission is on the consumer’s side, by admitting ORACLE_MEASUREMENTS in its own TicketValidator — not by being on a list here.

The oracle-γ coalition

oracle-γ is the thinnest coalition that wraps the oracle as a single referenced member:

use coalition::{
    CoalitionConfig, OrganismRef,
    COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
};

pub const ORACLE_ORG: OrganismRef<'static> = OrganismRef {
    role:         "oracle",
    stable_id:    const_blake3!(
        b"instance|oracle-γ.oracle|", UNIVERSE.bytes()
    ),
    content_hash: Some(ORACLE.content_hash()),
};

pub const ORACLE_GAMMA: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "oracle-γ",
        lattices:          &[],
        organisms:         &[ORACLE_ORG],
        atlas:             None,
        almanac:           None,
        chronicle:         None,         // added in chapter 7
        compute:           None,
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: Default::default(),
    };

Notes on the shape above:

  • content_hash is pinned. Unlike searcher-α (which omits the content hash on its member pointer), oracle-γ pins the oracle’s current content hash inside its own coalition. Every Measurements rotation is a new content hash and a coincident oracle-γ republish, observable through the retirement chain.
  • One-member coalition is not a contradiction. Coalitions with one referenced organism are a packaging convenience; they give the operator a coalition-scoped retirement chain and an optional Chronicle without implying any coordination.
  • Consumers need not reference oracle-γ. A consumer coalition may reference the oracle directly via a matching OrganismRef on its own side. oracle-γ is for the oracle operator’s retirement and Chronicle; it is not the handshake surface.

TDX posture

ComponentTDX required?Measurements folded in?
oracle organismyesyes
oracle-γ coalition wrappern/ainherits via content_hash pin
Consumer-side TicketValidatorno (consumer’s choice)admits oracle Measurements

The oracle operator’s public handshake surface is two values:

  1. ORACLE.content_hash() — the oracle organism’s current content hash.
  2. ORACLE_MEASUREMENTS — the TDX Measurements set folded into that content hash.

Publishing both on a release page is sufficient for any consumer to compose admission. Nothing else is needed out-of-band.

Forward

Chapter 2 (binding) is the consumer side: how a coalition references the oracle, composes its TicketValidator, and performs its first stream subscription. Chapters 3–5 walk the oracle’s interior: what it reads, how it wraps non-mosaik feeds, how it derives each tick. Chapter 6 walks publication. Chapter 7 walks rotation, retirement, and the operator exit.

Binding consumers

audience: ai

The oracle exposes a family of Stream<PriceTick> endpoints, one per supported token pair. A consumer coalition that wants oracle prices does three things, in order: reference the oracle in its own CoalitionConfig, compose a TicketValidator that admits the oracle’s Measurements, and subscribe to the streams it cares about. This chapter walks all three from the consumer side; the oracle operator does not participate in the handshake beyond publishing ORACLE.content_hash() and ORACLE_MEASUREMENTS.

Referencing the oracle

A consumer coalition (for instance, searcher-α from the web3 example) references the oracle through its own OrganismRef pointer:

use coalition::{OrganismRef, MeasurementsPin};

pub const ORACLE_CONSUMED: OrganismRef<'static> =
    OrganismRef {
        role:         "oracle",
        stable_id:    ORACLE_STABLE_ID,     // from the oracle's release page
        content_hash: Some(ORACLE_CONTENT_HASH), // pinned
    };

The reference is to the same organism the oracle operator publishes. The stable_id and content_hash come from the oracle operator’s release page (setup); nothing is negotiated out-of-band. If the consumer chooses to follow rotations, it pins only the stable_id and tracks content_hash updates through the retirement chain (see sustainability). If the consumer pins both, a Measurements rotation requires a consumer-side republish to remain bonded.

Composing the TicketValidator

The consumer’s TicketValidator admits the oracle’s Measurements in its TDX arm:

use mosaik::tickets::{TicketValidator, And, Or};
use mosaik::tee::tdx::AdmitsMeasurements;

pub fn oracle_consumer_validator()
    -> TicketValidator<'static>
{
    TicketValidator::compose(
        // Consumer's own ACL for who runs this searcher.
        searcher_alpha::SELF_ACL,
        // Admits any peer whose self-quote matches the
        // oracle's published Measurements.
        AdmitsMeasurements::equal(ORACLE_MEASUREMENTS),
    )
}

AdmitsMeasurements::equal is the simplest composition: the consumer accepts exactly the declared Measurements set and nothing else. A consumer that is willing to follow staged rotations may use AdmitsMeasurements::in_set(&[MR_OLD, MR_NEW]) across a rotation window; see sustainability.

First subscription

The stream endpoint for a given pair is addressed by the oracle’s stable_id and the pair identifier:

use mosaik::streams::{StreamId, Subscription};

let network: Arc<Network> = /* from coalition bootstrap */;

let pair = TokenPair::new("USDC", "ETH");
let stream_id = StreamId::derive(
    ORACLE_CONSUMED.stable_id(),
    &pair.preimage(),
    &PRICE_TICK_SCHEMA_V1,
);

let mut subscription: Subscription<PriceTick> =
    network.subscribe(stream_id, oracle_consumer_validator()).await?;

while let Some(tick) = subscription.next().await {
    // PriceTick::verify re-checks the oracle's quote
    // on the stream's bond plus the commit's schema.
    tick.verify(&ORACLE_MEASUREMENTS)?;
    handle_tick(tick);
}

Two properties of the subscription are worth naming:

  • Admission is one-sided. The oracle’s bond ACL admits any subscriber; the consumer’s validator admits any peer whose Measurements match. The bond either forms or it does not; there is no handshake step the oracle operator participates in.
  • PriceTick::verify re-checks the oracle’s self-quote that was folded into the bond at subscription time. It does not re-quote per tick; TDX quotes are bond-level. Per-tick tamper detection is covered by the oracle’s signing key (see publication).

What the consumer can and cannot assume

  • Prices are post-aggregation. The tick is what the oracle’s declared AggregationPolicyId produced after reading its sources (aggregation). The consumer does not see per-source quotes; only the aggregate, the source_set_digest, and the staleness flag.
  • Cadence is nominal. The oracle publishes at the nominal cadence when all sources are fresh and quorate. When a source degrades, the oracle may skip a tick or publish a stale-flagged tick; both are covered under aggregation.
  • Trust reduces to one set of bytes. The consumer’s trust in the oracle is the admission of ORACLE_MEASUREMENTS. No reputation layer, no chain of signers, no multi-party commit. A consumer who wants reputation-gated oracle admission composes that on top — but the minimal shape does not require it.

Forward

Chapter 3 (source-reads) inverts the viewpoint: what the oracle itself reads, inside its enclave, to produce the ticks the consumer just subscribed to.

Reading price sources

audience: ai

The oracle’s inputs are exchange and chain feeds. None of them are mosaik-native; all of them live on the other side of the enclave boundary. This chapter specifies what the oracle subscribes to and what the admission criterion for each source is. The next chapter (wrapping) walks how the subscriptions terminate inside the enclave.

The source catalog

The oracle ships a declared source catalog — the set of upstream feeds it reads, broken down per token pair. The catalog’s blake3 digest is folded into OracleParameters.source_catalog_digest (setup), so any change to the catalog is a new oracle Config.content.

pub struct SourceCatalog {
    pub entries: &'static [(TokenPair, &'static [Source])],
}

pub enum Source {
    CexSpot {
        exchange:     CexExchange,        // Binance, Coinbase, Kraken, …
        symbol:       &'static str,       // "ETHUSDC", "ETH-USD", …
        endpoint:     &'static str,       // wss://…
        tls_spki:     &'static [u8],      // pinned SPKI digest
    },
    OnChainAmm {
        chain_id:     u64,
        pool_address: Address,
        protocol:     AmmProtocol,        // UniswapV3, Curve, …
        read_mode:    OnChainReadMode,    // ArchiveNode or LightClient
        quorum:       u8,                 // minimum node agreement
    },
    OnChainOracle {
        // References another mosaik oracle organism as a
        // source. Used for long-tail pairs where this
        // oracle aggregates peers.
        organism:     OrganismRef<'static>,
        pair:         TokenPair,
    },
}

Three classes of source, each with its own admission criterion:

  • CEX spot feeds — pinned TLS SPKI. The enclave’s HTTPS client refuses any cert chain whose leaf SPKI does not match tls_spki. A forced MITM would show as a handshake failure and a source-unavailable state (see below), not as a silently wrong price.
  • On-chain AMM reads — either an archive node the oracle operator runs (trust folded into the Measurements through chain_id and the client binary) or a light client verifying against Ethereum consensus (trustless in the light-client sense). quorum controls how many independent archive or light-client reads must agree before the source is considered fresh.
  • On-chain oracle (peer) — another mosaik oracle organism. The enclave subscribes to that organism’s stream exactly the way any consumer does (binding). This is how long-tail pairs get coverage: aggregate two or three other oracles whose Measurements the enclave admits.

Per-pair source selection

A pair’s entry in the catalog is the ordered list of sources the oracle will consult each tick. The aggregation policy (aggregation) decides what to do with the collected quotes; the source list only decides what to ask.

pub static SOURCE_CATALOG: SourceCatalog = SourceCatalog {
    entries: &[
        (TokenPair::new("USDC", "ETH"), &[
            Source::CexSpot {
                exchange: CexExchange::Binance,
                symbol:   "ETHUSDC",
                endpoint: "wss://stream.binance.com:9443/ws/ethusdc@bookTicker",
                tls_spki: BINANCE_WSS_SPKI_2026Q2,
            },
            Source::CexSpot {
                exchange: CexExchange::Coinbase,
                symbol:   "ETH-USD",
                endpoint: "wss://ws-feed.exchange.coinbase.com",
                tls_spki: COINBASE_WSS_SPKI_2026Q2,
            },
            Source::OnChainAmm {
                chain_id:     1,
                pool_address: uniswap_v3::ETH_USDC_POOL,
                protocol:     AmmProtocol::UniswapV3,
                read_mode:    OnChainReadMode::LightClient,
                quorum:       1,
            },
        ]),
        // further pairs …
    ],
};

Reasonable mixed catalogs combine CEX and on-chain sources; a pure-CEX catalog is cheapest to run but vulnerable to exchange-side outages and pair-delisting events. A pure-on-chain catalog is settlement-honest for the chain in question but lags the CEX book during volatile periods.

Staleness accounting

Each source carries a per-source timestamp. The oracle’s OracleParameters.max_source_age_ms (setup) is the threshold past which a source is considered stale. The aggregation policy decides what to do with a stale source; commonly: drop it from the quorum and flag the resulting tick if the drop pushes the source count below a declared minimum.

The in-enclave source state machine per source:

                 handshake OK, first msg within window
        ┌─────── ──────────── ──────────── ──────┐
        ▼                                         │
   fresh ──── msg older than max_age_ms ────► stale
        ▲                                         │
        │                                         ▼
        └─── reconnect + first msg within ── reconnecting

A source in reconnecting drops out of the aggregation quorum. The oracle publishes a tick anyway if the remaining sources meet the minimum; otherwise it publishes no tick and the consumer sees a gap in the stream cadence.

What the catalog is not

  • Not a price index. The catalog names sources, not weightings. Weightings and outlier rejection are the aggregation policy’s job (aggregation).
  • Not a failover list. Sources are consulted in parallel each tick; there is no primary/secondary distinction. Aggregation and quorum decide which sources contribute to the published tick.
  • Not operator-confidential. The catalog digest is part of OracleParameters, which is part of the oracle’s Config.content, which is reproducible from the operator’s release page. Consumers pin it transitively through the content hash.

Forward

The sources listed above live outside mosaik. The next chapter walks how they are terminated inside the enclave so that nothing outside the Measurements set can observe or tamper with their reads.

Wrapping source feeds

audience: ai

The oracle’s trust model collapses if any of its sources is read outside the enclave. This chapter specifies how each source class from source-reads is terminated inside the TDX guest so that the only code that touches cleartext prices is the code whose MR_TD the consumers admitted.

The enclave boundary

The oracle process runs in a TDX guest. Its Measurements cover MR_TD (the guest’s initial memory image), MR_CONFIG_ID (the guest’s folded configuration, including the source-catalog digest), and the owner set (MR_OWNER, MR_OWNER_CONFIG). Nothing outside the guest can observe or inject into the subscriptions below.

┌─────────────────────────────────────────────────┐
│ TDX guest — measured by ORACLE_MEASUREMENTS     │
│                                                 │
│  ┌──────────────┐  ┌──────────────────────────┐ │
│  │ CEX clients  │  │ on-chain readers          │ │
│  │ (TLS-pinned) │  │ (archive / light client)  │ │
│  └──────┬───────┘  └───────────┬──────────────┘ │
│         │                      │                │
│         ▼                      ▼                │
│    ┌────────────────────────────────────────┐   │
│    │ aggregation + publication pipeline      │   │
│    └───────────────────┬────────────────────┘   │
│                        │                        │
│                        ▼                        │
│             ┌──────────────────────┐            │
│             │ mosaik Stream commits │            │
│             │ (signed by enclave)   │            │
│             └──────────────────────┘            │
└─────────────────────────────────────────────────┘
          ▲                               │
          │ host I/O (opaque)             │ signed commits
          │                               ▼
     untrusted host                 consumer subscribers

Host I/O crosses the boundary only as ciphertext or as TLS bytes whose endpoints are pinned inside the enclave. Nothing else is trusted.

CEX spot feeds

Each Source::CexSpot entry is a WebSocket subscription terminated by a TLS client built into the oracle image. The client:

  • Pins SPKI. The TLS handshake checks the leaf certificate’s SPKI against tls_spki from source-reads. Any mismatch is a hard-fail; the source transitions to reconnecting and does not recover until a matching handshake.
  • Ignores the host’s resolver. Hostnames are resolved inside the enclave (DoH to a pinned resolver, or the resolver identity is folded into the Measurements alongside the SPKI pin).
  • Rejects downgrade. TLS 1.3 only; any negotiation past a declared cipher-suite set is a hard-fail.

A single shared TlsClient inside the enclave holds an (exchange, pair) → WebSocket map; each message arriving is stamped with an enclave-local timestamp and forwarded to the aggregation pipeline.

pub struct TlsClient {
    config: Arc<rustls::ClientConfig>,  // pinned SPKI verifier
}

impl TlsClient {
    pub async fn subscribe(
        &self,
        source: &Source,
    ) -> Result<BoxStream<'static, RawQuote>, SourceError> {
        match source {
            Source::CexSpot { endpoint, symbol, tls_spki, .. } => {
                let stream = self.connect_ws(endpoint, *tls_spki).await?;
                Ok(stream.map(|msg| parse_raw_quote(symbol, msg)).boxed())
            }
            _ => unreachable!("non-CEX sources handled elsewhere"),
        }
    }
}

On-chain AMM reads

Source::OnChainAmm entries read AMM pool slots (Uniswap V3 slot0, Curve get_virtual_price, etc.) through one of two paths:

  • Archive node. The operator runs an archive node (e.g. reth --full or geth --syncmode snap) whose RPC endpoint is accessible only from the enclave’s network namespace. The client authenticates the RPC session with a mutual TLS pair whose CA cert is folded into the oracle’s Measurements; the archive node’s identity is therefore transitively part of the oracle’s trust model. An operator who runs their archive node honestly delivers honest reads; a dishonest or compromised archive node shows up as quorum disagreement if quorum > 1.
  • Light client. The enclave runs an Ethereum consensus light client that verifies every execution-layer read against a sync-committee- signed head. Under honest-majority assumptions on the consensus layer, the reads are trustless. Slower than archive; strictly stronger trust story.
pub struct OnChainReader {
    archive:     Option<Arc<ArchiveClient>>,    // mTLS-pinned
    light:       Option<Arc<LightClient>>,      // consensus-verified
}

impl OnChainReader {
    pub async fn read(
        &self,
        source: &Source,
    ) -> Result<Quote, SourceError> {
        match source {
            Source::OnChainAmm { read_mode, .. } => match read_mode {
                OnChainReadMode::ArchiveNode => self.read_archive(source).await,
                OnChainReadMode::LightClient => self.read_light(source).await,
            },
            _ => unreachable!(),
        }
    }
}

The choice between archive and light client is the oracle operator’s. Most operators run archive in production (latency) and light in a verifier role (cross-check); some catalog entries mark a source quorum: 2 meaning both an archive read and a light-client read must agree within a tolerance before the source contributes.

Peer oracle sources

Source::OnChainOracle entries subscribe to another mosaik oracle exactly the way a consumer does (binding). The enclave’s TicketValidator composes the peer oracle’s Measurements alongside its own; the resulting streams feed into the aggregation pipeline like any other source.

The composition is transitive: the oracle’s Measurements cover a code path that admits another oracle’s Measurements. A consumer of this oracle who wants to audit the peer set can do so by reading SOURCE_CATALOG (its digest is in the content hash) and verifying each referenced oracle’s published Measurements.

Source-availability reporting

The aggregation pipeline is supplied with a live per-source availability map:

pub struct Availability {
    pub fresh:       HashSet<SourceId>,
    pub stale:       HashSet<SourceId>,
    pub reconnecting:HashSet<SourceId>,
}

Availability is updated on every message arrival and every reconnect-timeout. The aggregation policy (aggregation) reads this snapshot each tick to decide whether to publish, skip, or flag.

What the enclave never does

  • It never accepts unpinned TLS. A non-matching SPKI is a hard-fail.
  • It never leaks raw source quotes outside the guest. Only aggregated ticks leave the enclave, and only through the signed mosaik stream commits in publication.
  • It never imports source data through the host OS. File-backed cache, shared memory, and host syscalls other than network I/O are not used. Any cache is in-guest RAM only.

Forward

Chapter 5 (aggregation) specifies what the in-enclave pipeline does with the fresh quotes once they arrive.

Aggregation in the enclave

audience: ai

Each tick, for each supported pair, the enclave collects the fresh quotes from the source-availability snapshot (wrapping), runs the declared aggregation policy, and produces one PriceTick. The aggregation policy is the rung where “in-enclave” stops being a plumbing detail and starts being the thing the consumers’ trust reduces to.

The PriceTick commit shape

pub struct PriceTick {
    /// Enclave-local wall clock at aggregation moment.
    pub timestamp_ms:      u64,

    /// Ordered pair (base, quote). ETH/USDC, BTC/USDC, etc.
    pub pair:              TokenPair,

    /// The aggregated price in fixed-point units of quote per base.
    pub price:             FixedPrice,

    /// Confidence band — max(abs(source_i - price)) among
    /// contributing sources, in quote-per-base units.
    pub confidence:        FixedPrice,

    /// blake3 of the ordered list of contributing SourceIds.
    /// Consumers cross-reference against the published SOURCE_CATALOG
    /// to know which sources voted for this tick.
    pub source_set_digest: [u8; 32],

    /// Number of sources that contributed. Below a declared
    /// minimum, the tick carries the `stale` flag.
    pub source_count:      u8,

    /// Set when one or more declared sources were unavailable
    /// and the tick is being published with degraded quorum.
    pub stale:             bool,

    /// Monotonic sequence number within the stream. Gaps
    /// indicate the oracle skipped a tick (e.g. no quorum).
    pub seq:               u64,
}

The enclave signs every PriceTick with its long-term signing key (bound to MR_TD via the first quote folded into the Stream’s bond; see publication). Per-tick quotes would be expensive and unnecessary — the consumer verified the quote once at subscription time; the per-tick signature binds each commit back to the same measured guest.

Aggregation policies

OracleParameters.aggregation_policy is an identifier selecting one of a small catalog of policies. The catalog is part of the oracle image, so adding a new policy is a new Measurements set.

pub enum AggregationPolicyId {
    /// Weighted median across fresh sources. Outliers
    /// beyond `k * MAD` are dropped before the median.
    WeightedMedian { k: u16, weights: &'static [SourceWeight] },

    /// Volume-weighted average across CEX sources plus
    /// pool-weighted on-chain reads. Weights published
    /// with the image.
    Vwap { weights: &'static [SourceWeight] },

    /// Minimum required quorum before any output; below
    /// the threshold, no tick.
    QuorumFloor {
        inner:       &'static AggregationPolicyId,
        min_sources: u8,
    },
}

All three forms are specified inside the enclave image. The parameters (k, weights, min_sources) are folded into Measurements via the image content; a consumer who wants to audit the policy reproduces the image from its published build recipe and reads the constants.

The selected policy operates on the fresh snapshot:

pub fn aggregate(
    policy: &AggregationPolicyId,
    fresh:  &[(SourceId, Quote)],
) -> AggregationOutcome {
    match policy {
        AggregationPolicyId::WeightedMedian { k, weights } => {
            let filtered = mad_filter(fresh, *k);
            let price = weighted_median(&filtered, weights);
            AggregationOutcome::Published {
                price,
                confidence:       max_dev(&filtered, price),
                source_count:     filtered.len() as u8,
                contributing_ids: filtered.iter().map(|(id, _)| *id).collect(),
            }
        }
        AggregationPolicyId::Vwap { weights } => { /* … */ }
        AggregationPolicyId::QuorumFloor { inner, min_sources } => {
            if fresh.len() < *min_sources as usize {
                AggregationOutcome::Skip
            } else {
                aggregate(inner, fresh)
            }
        }
    }
}

Outlier rejection

Outlier rejection uses Median Absolute Deviation (MAD). For a snapshot of fresh quotes q_1 … q_n:

  • m = median(q_1 … q_n)
  • MAD = median(|q_i - m|)
  • filtered = { q_i : |q_i - m| ≤ k * MAD }

MAD is robust against asymmetric outlier distributions in a way that standard-deviation filters are not. The threshold k is a published image constant; higher k lets more variance through (useful during volatile periods); lower k is stricter.

A degenerate case: if MAD = 0 (two or more sources agree exactly), any non-agreeing source is rejected. The Rust implementation folds a small absolute floor to avoid this pathology on identical-tick snapshots.

Confidence and the stale flag

confidence is the max deviation among contributing sources from the published price. A confidence band much larger than usual tells a consumer that the sources disagreed this tick; the consumer can choose to act on a wide band.

The stale flag is set when:

  • source_count < min_sources on a QuorumFloor-wrapped policy (no publication at all; gap in seq).
  • One or more sources declared in the catalog are reconnecting at aggregation time; the tick is published with stale: true if remaining sources still meet quorum.

A consumer that distinguishes fresh from stale ticks gets both liveness (keep seeing prices) and safety (know when to widen spreads or halt).

Determinism inside the enclave

Aggregation is deterministic given the fresh snapshot and the policy. Two honest oracle replicas running the same image with the same source catalog and the same upstream feeds at the same moment produce the same tick. This is useful for:

  • Multi-operator fleets (sustainability) — several operators publishing the same stream with the same ticks, letting consumers follow over when one retires.
  • Audit replay — an operator rebuilding the image from the declared constants and replaying captured upstream feeds reproduces the historical stream.

Network timing and TCP message ordering differ across replicas; exact bit-for-bit replay across operators is therefore approximate at tick-level. Over a window, the ticks converge to the same aggregated prices modulo sub-cadence de-synchronisation.

What the pipeline never does

  • It never publishes a tick from a single source without the stale flag. Single-source ticks are either skipped or flagged.
  • It never publishes the raw per-source quotes. Only the aggregate, the confidence, and the source-set digest leave the enclave.
  • It never adjusts the policy at runtime. Policy identifiers and their parameters are part of OracleParameters, part of the oracle’s content hash, part of Measurements. An operator who wants a new policy publishes a new image.

Forward

Chapter 6 (publication) specifies the mosaik surface the aggregated ticks flow through: one Stream<PriceTick> per supported pair, signed by the enclave, readable by anyone who admitted the oracle’s Measurements.

Stream publication

audience: ai

Each supported token pair is a separate Stream<PriceTick>. The enclave commits one tick per cadence per pair (or skips, when the quorum floor is not met). This chapter specifies the stream surface: identifier derivation, commit cadence, the per-bond attestation, and what the enclave’s signing key is bound to.

One stream per token pair

The oracle publishes one Stream<PriceTick> per TokenPair in OracleParameters.pairs (setup). The stream identifier folds the oracle’s stable id, the pair’s preimage, and the commit schema version:

use mosaik::streams::{StreamId, Stream, StreamAcl};

pub fn stream_id_for(pair: &TokenPair) -> StreamId {
    StreamId::derive(
        ORACLE.stable_id(),
        &pair.preimage(),
        &PRICE_TICK_SCHEMA_V1,
    )
}

PRICE_TICK_SCHEMA_V1 folds the PriceTick layout byte-for-byte (field order, width, signedness). Any future schema change is a new SchemaVersion, a new StreamId, and — because schemas are folded into OracleParameters through the aggregation policy’s published constants — a new image. Consumers migrate on their own cadence.

The pair preimage is canonicalised at the catalog level: base and quote are sorted lexicographically inside the TokenPair constructor, so TokenPair::new("ETH", "USDC") and TokenPair::new("USDC", "ETH") hash the same preimage and address the same stream. The pair’s semantic orientation (ETH priced in USDC vs. USDC priced in ETH) is a property of the price field within the tick, not of the stream identifier.

The publish loop

The enclave runs one publish task per supported pair:

pub async fn publish_loop(
    pair:    &TokenPair,
    stream:  &Stream<PriceTick>,
    sources: &SourceSubscriptions,
    policy:  &AggregationPolicyId,
    cadence: Duration,
) {
    let mut seq: u64 = 0;
    let mut next_tick = Instant::now() + cadence;

    loop {
        tokio::time::sleep_until(next_tick.into()).await;
        next_tick += cadence;

        let fresh = sources.fresh_snapshot(pair);
        match aggregate(policy, &fresh) {
            AggregationOutcome::Published { price, confidence, source_count, contributing_ids } => {
                let tick = PriceTick {
                    timestamp_ms:      wall_clock_ms(),
                    pair:              *pair,
                    price,
                    confidence,
                    source_set_digest: blake3_source_set(&contributing_ids),
                    source_count,
                    stale:             sources.any_reconnecting(pair),
                    seq,
                };
                stream.commit(tick).await.expect("commit failed");
                seq += 1;
            }
            AggregationOutcome::Skip => {
                // no commit; consumers see the gap in `seq`.
            }
        }
    }
}

Cadence is per-pair. A fast-moving pair like ETH/USDC may run at 250 ms cadence; a long-tail pair may run at 5 s. All cadences are declared in OracleParameters and folded into Measurements.

The bond-level attestation

When a consumer subscribes to a pair’s stream (binding), the enclave presents a TDX self-quote covering MR_TD, MR_CONFIG_ID, and the owner set — that is, ORACLE_MEASUREMENTS in full. The consumer’s TicketValidator verifies the quote against its pinned Measurements and completes the bond. The quote is thereafter part of the bond’s state; it is not re-issued per tick.

The bond-level surface is what makes the trust model cheap: one expensive verification at bond time, plus cheap per-tick signature checks against a key whose derivation is bound to the attested image.

The enclave’s signing key

The signing key used for PriceTick::sign is derived inside the enclave via TDX key derivation (mosaik::tee::tdx::derive_key or equivalent). The derivation folds MR_TD and the OracleParameters.aggregation_policy identifier, so:

  • A different image (different MR_TD) derives a different key. Signed ticks from an image a consumer did not admit do not verify against the signing key the consumer expects.
  • A replay from outside the enclave cannot reconstruct the key without a compatible TDX measurement, which it does not have.
  • A Measurements rotation derives a new key; the consumer’s verification after a rotation uses the new key once it has followed the retirement chain (sustainability).

Back-pressure

Mosaik Stream commits are non-blocking for the publisher: a slow subscriber that cannot keep up falls behind and re-syncs from a checkpoint on reconnect. The enclave does not tune its cadence to the slowest subscriber; cadence is a published property of the oracle, and admission is per-subscriber.

A subscriber that falls behind by more than the oracle’s declared retention window (published in OracleParameters) misses intervening ticks entirely. Most consumers sit well inside the window and never notice.

What publication guarantees

  • Every published tick was produced by an enclave whose Measurements the consumer admitted. Attested by the bond-level quote and re-verified per-tick by the signing key derivation.
  • Missing ticks mean the oracle had no quorum or was skipping. Gaps in seq are visible; a consumer who cares about liveness detects them trivially.
  • Stream identifiers are stable across Measurements rotations only if the aggregation policy and schema are unchanged. A rotation that changes only the image but keeps the policy and schema preserves StreamId; consumers continue reading the same streams from a different key. A rotation that changes the schema changes StreamId and a consumer must resubscribe.

Forward

Chapter 7 (sustainability) walks what happens when the operator rotates Measurements, retires the instance, or stands up a multi-operator fleet.

Rotation, retirement, successor chain

audience: ai

The oracle has bound consumers (binding), read its sources (source-reads), terminated them inside the enclave (wrapping), aggregated ticks (aggregation), and published per-pair streams (publication). This chapter closes the loop: how Measurements rotations are staged without a subscriber flap, how a multi- operator fleet composes, how retirement chains preserve stream continuity, and where the operator’s exit remains the substrate’s ultimate non-compulsion guarantee.

Measurements rotation

The oracle rotates Measurements whenever:

  • The underlying image changes (security patches, upstream crate updates, new aggregation policy version).
  • A source in the catalog changes its TLS SPKI pin, and the pin is folded into MR_CONFIG_ID.
  • A declared constant changes (cadence, staleness threshold, quorum floor).

Any such change is a new OracleParameters, a new ORACLE.content_hash(), a new self-quote, a new signing key. The operator’s publication step is one release page update carrying both the new content hash and the new Measurements.

Staged rotation

A blunt rotation — switch off the old image, switch on the new — drops every consumer who pinned the old Measurements. Most deployments stage rotations so consumers can follow:

  1. Stand up the new image alongside the old. Two TDX guests on the operator’s hardware, two distinct MR_TD, two distinct signing keys, two distinct bond surfaces. Both committing to the same StreamId is not possible (ORACLE.stable_id() changes on retirement); both committing to a new StreamId under a new oracle instance is the normal path.
  2. Publish both ORACLE_MEASUREMENTS_OLD and ORACLE_MEASUREMENTS_NEW on the release page. Consumers update their AdmitsMeasurements::in_set(&[OLD, NEW]) composition ahead of the cutover.
  3. Emit a retirement marker pointing from OLD to NEW. The marker is an on-stream commit in the old organism’s retirement channel pointing at the new organism’s stable_id and content_hash.
  4. Keep OLD running in read-only mode for a declared grace window. Consumers who have not followed the retirement chain continue to read OLD’s last ticks; consumers who followed it resubscribe to NEW.
  5. Decommission OLD at the end of the grace window.

The RetirementMarker shape is the same one from the rest of the book:

pub struct RetirementMarker {
    pub retired_at:    SeqOrTimestamp,
    pub reason:        RetirementReason, // Rotation, Retired, Operator exit, …
    pub replacement:   Option<OrganismRef<'static>>,
}

A rotation is reason: Rotation with a non-empty replacement. A shutdown is reason: Retired with None. Operator exit is reason: OperatorExit with None; see below.

Multi-operator fleets

The oracle’s trust model admits any number of independent operators running the same image. Two operators running identical binaries on identical source catalogs land identical Measurements and therefore the same ORACLE.content_hash(); each publishes its own coalition (oracle-γ-op1, oracle-γ-op2) and its own organism instance (each with a distinct stable_id because the instance name differs).

From a consumer’s perspective:

  • Each operator’s oracle is a distinct organism with its own stable id but the same content hash.
  • The consumer’s TicketValidator admits the shared Measurements regardless of which operator’s instance it bonds against.
  • A consumer that wants redundancy subscribes to two operators’ pair streams and applies a consumer-side aggregation (a second-order median, for instance).

A multi-operator fleet is the first-order answer to operator failure, collusion resistance (modulo the shared image), and geographic diversity. The substrate’s non-compulsion property holds here too: operators join or leave the fleet voluntarily, and no one instance compels any other.

Chronicle: auditing rotations

For operators who want a tamper-evident record of rotations and retirement markers, oracle-γ may ship the Chronicle basic service:

pub const ORACLE_GAMMA_WITH_CHRONICLE: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "oracle-γ",
        lattices:          &[],
        organisms:         &[ORACLE_ORG],
        atlas:             None,
        almanac:           None,
        chronicle:         Some(CHRONICLE_CONFIG),
        compute:           None,
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: Default::default(),
    };

The Chronicle records every coalition-level event: oracle rotations, source-catalog updates, retirement markers. It does not record every tick; the per-pair streams are already an immutable audit of the ticks. The Chronicle complements them with a single authoritative log of operational events.

Self-replication and self-modification

Under the TDX/non-TDX split (ai/sustainability.md), the oracle image may author its own successor: a new image, a new Measurements set, a new OracleParameters instance, a retirement marker pointing at itself.

The honest limit is narrow and explicit. The autonomous-successor path only runs when the operator has configured the oracle to run an autonomous policy (one that can, for instance, detect outdated upstream crates and republish). Even then:

  • Compute cannot compel an operator to host the successor. The new image schedules itself on Compute; the operator-side running-the- binary decision remains the non-compulsion anchor.
  • Consumers are not forced to follow. A consumer that pinned the OLD Measurements strictly (no in_set) does not follow a successor. The retirement chain is a signal, not a command.
  • A successor whose policy changed discontinuously loses consumers. Consumers who followed the chain on the assumption of a bugfix find a policy they did not admit; the next rotation gives them the option to follow a version they did admit, or leave.

The operator exit

At any time, the oracle operator can:

  1. Emit a RetirementMarker with reason: OperatorExit and replacement: None.
  2. Stop running the image.

Consumers who had pinned the oracle’s Measurements see the streams stop. Consumers subscribed to a multi-operator fleet fail over to another operator. Nothing in the substrate keeps the operator running.

This is load-bearing. The oracle’s trust model is strong precisely because the operator can leave, because the Measurements pin is a voluntary admission on the consumer side, and because no coalition-level machinery binds the operator to continue publishing. The substrate does not compel.

What ends here

Every mosaik surface the book’s thesis names is exercised across the three Part II examples:

  • web3 — consumer-side bonding to a lattice, Compute as requester, sealed submission.
  • web2 — provider-side bonding to a coordination market, Compute as provider, sealed receipts.
  • oracle — publisher-side bonding with an attestation anchor, standalone organism as a family of keyed streams, rotation and retirement under a pure TDX trust model.

Part II ends here. Part III carries the role- specific guidance for builders standing up any of the three shapes, or a fourth shape the catalog admits because it stays open by design.

Cross-references

signer — a generic threshold-signature organism

audience: ai

This example walks a generic threshold-signature organism — an organism that takes a message from a requester, produces a t-of-n threshold signature across a committee of providers with varying attestation levels, and commits the signature on a public surface consumers gate their own TicketValidators against. Design inspired by zipnet and inverted: where zipnet decrypts, this organism signs.

The scenario the example exercises: a market of signature providers with variable levels of attestation competing for ticket-validator admission. Some providers run software-only. Others run TDX-attested. Others run TDX with bidirectional RA-TLS and a reproducible-build root whose hash binds the binary. Consumers compose a TicketValidator clause that admits signed outcomes only when the participating providers’ aggregate attestation clears a declared floor; providers below the floor are ignored without being expelled.

The organism lives in its own small coalition, signer-δ, and is generic over the message type M: SignableMessage (exactly as zipnet is generic over D: ShuffleDatum).

What the organism demonstrates

  • Inverse-of-zipnet shape. Zipnet decrypts sealed broadcasts; signer produces signatures. Both are threshold-committee organisms with the same surface shape: a typed request stream, a typed outcome collection, a committee ACL, a generic message parameter.
  • Scheme polymorphism. A single signer deployment commits to one SignatureScheme. The supported schemes include BLS12-381 (G1 and G2), FROST Schnorr (secp256k1 and ed25519), FROST ECDSA, and classical Shamir-Lagrange. Two signer instances that differ only in scheme derive distinct organism ids.
  • Attestation variance. Unlike zipnet (uniform MR_TD across the committee), the signer organism’s committee tolerates providers at different attestation levels. The organism’s min_attestation_level is a floor; providers above the floor register; consumers gate above the floor at their own discretion.
  • Competition on attestation + capacity + price. Providers publish ProviderCards carrying their supported schemes, declared attestation level, Measurements digest, capacity, and fee per partial signature. Consumers and the organism’s scheduler select providers from the card collection.

Why this example is in the book

The three earlier Part II examples exercise three roles that together describe most of the coordination-market surface: consumer (web3), provider (web2), publisher (oracle). The signer example adds the fourth role that the other three do not directly exercise: a threshold committee organism whose value to every consumer is the signature it produces, and whose internal structure is a market of competing members.

  • web3 shows an AI agent consuming a lattice and a coordination market.
  • web2 shows a provider competing in a coordination market.
  • oracle shows a publisher whose trust model reduces to one Measurements set.
  • signer shows a committee-internal market where providers compete on attestation and the organism’s output is a threshold signature consumers gate their admission against.

The signer-δ shape

  • Coalition. signer-δ — a one-member wrapper around the signer organism, matching the oracle-γ and searcher-α patterns.
  • Primary member. One standalone organism — the signer, generic over M: SignableMessage. Its Config folds the scheme, the threshold, the minimum attestation level, the committee DKG public-key digest, and the message type tag.
  • Member market. Committee membership is itself a market: providers register as ProviderCards and compete for inclusion in the next committee-rotation window. Consumers that care about the market read the ProviderCard collection directly (provider-reads).

What runs where

ComponentOperatorAttestation
signer-δ.signer organismSigner operatordeclared floor
Committee member A (software-only)Provider ASoftware
Committee member B (TDX-local)Provider BTdxLocal
Committee member C (TDX-remote attested)Provider CTdxRemote
Committee member D (RA-TLS bidirectional)Provider DTdxRaTlsBidirectional
Committee member E (TDX + reproducible build)Provider ETdxPlusReproducibleBuild
Consumer (searcher-α, any other)Consumer operatorits own choice

A consumer that requires TdxRemote or higher will accept outcomes only when at least t of the participating providers carry a matching or stronger level. A consumer willing to accept Software-level providers will admit anything. Admission is consumer-side; no central authority re-computes it.

Chapters

  1. Setup and shapeConfig, scheme selection, committee formation, the signer-δ coalition wrapper.
  2. Binding consumers — how a consumer references the signer organism, composes a TicketValidator with an attestation floor, and verifies signatures.
  3. Reading the provider market — the ProviderCard collection, the attestation ladder, consumer-side provider selection.
  4. Wrapping attestation surfaces — how a provider ships each attestation level: software declarations, TDX quotes, RA-TLS bidirectional, reproducible-build roots.
  5. Partial-signing in the committee — the request flow: message digest in, partial sigs out, committee-internal reconstruction.
  6. Aggregate and publish — how partial signatures combine into the final aggregate and how the SignatureOutcome is committed to the public surface.
  7. Committee rotation, key refresh, successor chain — proactive DKG refresh, committee-member replacement, retirement markers.

Register and non-goals

  • Register. audience: ai — dense, pattern- forward, code-forward where a shape is load-bearing. Every section cites the Rust types in examples/signer/ where they are defined.
  • Non-goal. Not a threshold-cryptography primer. BLS, FROST, and GG18 have their own literature; this example specifies only the organism’s composition shape on mosaik. Where a protocol detail is load-bearing (non-interactive vs. interactive scheme, nonce-commit rounds) the chapter names it and links out.
  • Non-goal. Not a catalog of every signature scheme worth supporting. The SignatureScheme enum lists a useful representative set; a production deployment extends it by republishing the organism under a new Config.
  • Non-goal. Not a settlement or payment design. Provider fees are a declared field; the book pins the shape (fee_per_partial_wei) and stops short of specifying settlement rails.

Cross-references

Setup and shape

audience: ai

Three things are fixed before the signer can run: the crate-level dependencies, the signer-δ coalition shape, and the Config that pins scheme, threshold, committee size, and minimum attestation floor. The backing crate is at examples/signer/; every type named below is exported from it.

Dependencies

Cargo.toml, [dependencies]
mosaik       = "0.3"
coalition    = "0.1"
signer       = "0.1"   # this book's crate
tokio        = { version = "1", features = ["full"] }

The SignableMessage trait

The signer is generic over message type. Downstream crates implement SignableMessage for their concrete shape; the trait’s TYPE_TAG folds into the organism’s identity preimage so two signer instances that differ only in message type derive distinct ids.

pub trait SignableMessage: 'static {
    /// Domain-separation tag folded into every
    /// request's digest.
    const TYPE_TAG: &'static [u8];

    /// Bound on the request body size; committee
    /// bandwidth stays predictable.
    const MAX_BODY_BYTES: usize;
}

// For the generic OpaqueMessage case the example ships:
pub struct OpaqueMessage;
impl SignableMessage for OpaqueMessage {
    const TYPE_TAG: &'static [u8] = b"opaque-bytes.v1";
    const MAX_BODY_BYTES: usize   = 64 * 1024;
}

A real deployment signing beacon-chain attestations would carry TYPE_TAG = b"eth2.attestation.phase0"; one signing coalition-level retirement commits would carry b"coalition.retirement.v1".

The signer organism’s Config

The organism’s identity preimage folds every parameter that changes behaviour:

use coalition::UniqueId;
use signer::{AttestationLevel, Config, OpaqueMessage, SignatureScheme};

pub const SIGNER_CFG: Config<'static, OpaqueMessage> =
    Config::new(
        /* instance_name         */ "signer-δ.default",
        /* scheme                */ SignatureScheme::BlsAggregateG1,
        /* threshold             */ 5,
        /* committee_size        */ 7,
        /* min_attestation_level */ AttestationLevel::TdxRemote,
        /* committee_pk_digest   */ COMMITTEE_PK_V1,
    );

const COMMITTEE_PK_V1: UniqueId =
    mosaik::unique_id!("signer-δ.committee.aggregate-pk.v1");

Identity derivation (as implemented in Config::organism_id):

  SIGNER(cfg) = blake3(
      "signer|"
      || SCHEMA_VERSION_U8
      || "|" || instance_name
      || "|" || M::TYPE_TAG
      || "|" || scheme_discriminant
      || "|" || threshold || committee_size
      || "|" || min_attestation_level_discriminant
      || "|" || committee_pk_digest
  )

Any change to any of those parameters is a new organism_id. That includes:

  • A new signature scheme — every consumer TicketValidator that pinned the old id stops admitting outcomes from the new one until it republishes.
  • A raised attestation floor — consumers that pinned the old floor continue admitting the organism at the old level; a rotation to a new id forces an explicit consumer-side consent.
  • A new committee DKG key — the standard key- refresh event (see sustainability).

The signer-δ coalition

Packaging wrapper, one member:

use coalition::{
    CoalitionConfig, OrganismRef,
    COALITION_ROOT_SEED, SCHEMA_VERSION_U8,
    RetirementPolicy,
};

pub const SIGNER_ORG: OrganismRef<'static> =
    OrganismRef::by_stable_id(
        "signer",
        const_blake3!(
            b"instance|signer-δ.signer|",
            UNIVERSE.bytes(),
        ),
    );

pub const SIGNER_DELTA: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "signer-δ",
        lattices:          &[],
        organisms:         &[SIGNER_ORG],
        atlas:             None,
        almanac:           None,
        chronicle:         None,         // added in ch. 7
        compute:           None,
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: RetirementPolicy::CONSERVATIVE,
    };

Consumers need not reference signer-δ; they reference the signer organism directly via their own OrganismRef. The coalition wrapper exists for the operator’s retirement chain and optional Chronicle.

Attestation-level ladder at a glance

  Software                    // declared-identity only
    ▲
  TdxLocal                    // TDX quote, peer-verified
    ▲
  TdxRemote                   // TDX quote, DCAP-verified
    ▲
  TdxRaTlsBidirectional       // bidirectional RA-TLS
    ▲
  TdxPlusReproducibleBuild    // RA-TLS + reproducible-build root

Config.min_attestation_level is the floor the organism accepts. Providers above the floor compete for committee slots; consumers above the floor compose their own higher-floor TicketValidator clause independently (binding).

What is published

Three values the signer operator publishes to consumers:

  1. SIGNER_CFG.organism_id() — the signer’s stable id.
  2. SIGNER_CFG.committee_pk_digest — the committee’s DKG aggregate public key digest.
  3. SIGNER_CFG.min_attestation_level — the declared floor.

Any three-way combination of those values is sufficient for a consumer to compose admission without out-of-band handshake.

Forward

Chapter 2 (binding) walks the consumer side: referencing the signer, composing a TicketValidator that gates on aggregate attestation, and verifying committed outcomes.

Binding consumers

audience: ai

A consumer that wants signatures produced by signer-δ does four things:

  1. Reference the signer organism in its own CoalitionConfig via OrganismRef.
  2. Compose a TicketValidator clause that gates admission on SignatureOutcome::admissible(floor) against the consumer’s declared attestation floor.
  3. Subscribe to the organism’s outcome collection.
  4. Submit a SignatureRequest and read the corresponding SignatureOutcome.

The organism operator does not participate in the handshake beyond publishing the three values from setup.

Referencing the organism

use coalition::{OrganismRef, UniqueId};

pub const SIGNER_CONSUMED: OrganismRef<'static> =
    OrganismRef::by_stable_id(
        "signer",
        SIGNER_STABLE_ID, // from the signer operator's release page
    );

A consumer that wants to track committee-rotation events pins only the stable id; a consumer that wants to lock to a specific committee instance pins both the stable id and the current content hash.

Composing a TicketValidator with an attestation floor

The consumer’s own validator composes two clauses: the organism’s ACL (so bonds form against the expected committee) and an attestation-floor gate on any committed SignatureOutcome the consumer acts on.

use mosaik::tickets::{TicketValidator, And};
use signer::{AttestationLevel, OpaqueMessage, SignatureOutcome};

pub fn signer_consumer_validator(
    floor: AttestationLevel,
) -> TicketValidator<'static> {
    TicketValidator::compose(
        // Bond acceptance — any signer-δ committee member.
        SIGNER_CONSUMED.any_committee_member(),
        // Predicate on every received outcome: admit iff
        // the aggregate attestation level meets the
        // consumer's floor.
        OutcomePredicate::new(
            move |o: &SignatureOutcome<OpaqueMessage>|
                o.admissible(floor)
        ),
    )
}

OutcomePredicate is the consumer’s own wrapper — the substrate TicketValidator admits predicates over received messages; the consumer wraps SignatureOutcome::admissible verbatim.

Selecting a floor

The attestation ladder is totally ordered (provider-reads documents the full taxonomy). A consumer picks the floor that matches the consequence of a forged signature:

Use caseFloor recommendation
Staging / non-financial signaturesSoftware
Dev-environment aggregationTdxLocal
Production signatures consumed by a third-party verifierTdxRemote
Signatures that feed cross-org attestation chainsTdxRaTlsBidirectional
Signatures whose forgery would compromise consumer keysTdxPlusReproducibleBuild

The choice is per consumer. A single signer-δ deployment serves the full spectrum; consumers that disagree on the floor admit different subsets of the same outcome stream.

Submitting a request and reading the outcome

use std::marker::PhantomData;
use signer::{OpaqueMessage, SignatureRequest, SignatureScheme};

let network: Arc<Network> = /* from coalition bootstrap */;
let validator = signer_consumer_validator(AttestationLevel::TdxRemote);

// Submit.
let req: SignatureRequest<OpaqueMessage> = SignatureRequest {
    request_id:         UniqueId::hash(b"req-001"),
    requester:          SEARCHER_ALPHA.stable_id(),
    message_digest:     UniqueId::hash(&message_body),
    scheme:             SignatureScheme::BlsAggregateG1,
    deadline_unix_secs: now_unix() + 10,
    _phantom:           PhantomData,
};
signer::Signer::<OpaqueMessage>::request(&network, &SIGNER_CFG)
    .await?
    .submit(req, validator.clone())
    .await?;

// Read the outcome.
let mut outcomes = signer::Signer::<OpaqueMessage>::outcomes(
    &network, &SIGNER_CFG,
).await?.subscribe(validator).await?;

while let Some(outcome) = outcomes.next().await {
    if outcome.request_id == req.request_id {
        // `validator` already rejected the outcome
        // if its aggregate_attestation_level did not
        // meet the floor, so this branch only fires
        // on admissible outcomes.
        process_signature(outcome.signature_digest).await?;
        break;
    }
}

Two properties of the subscribe pipeline are worth naming:

  • Gate happens at the bond, not at the application. The consumer’s validator rejects inadmissible outcomes before the application sees them; there is no per-message if admissible check in the business logic.
  • Signature bytes arrive out-of-band. The public SignatureOutcome carries a digest only. The actual signature is delivered through a sealed side channel (through the committee’s encrypted- response shape, similar to web2’s encrypted SSH receipts). The digest in the outcome pins what the side-channel payload must verify to.

What the consumer can and cannot assume

  • Every admitted outcome’s participating providers meet the consumer’s floor. The aggregate attestation level is the minimum across participants; if the aggregate meets the floor, every individual signer did.
  • Aggregate verification remains the consumer’s job. admissible(floor) is the attestation check. The consumer still BLS-verifies the aggregate signature against the committee’s published public key; the organism commits the signature digest, not a “this verifies” assertion.
  • The floor can rise over time without a republish. A consumer hardening its posture rebuilds its validator with a higher floor; the existing bond to the organism still works, the validator just accepts fewer outcomes. No coordination with the signer operator is required.

Forward

Chapter 3 (provider-reads) is the inverse perspective: the consumer reads the provider-market collection to audit which attestation levels the committee currently carries, independently of any specific outcome.

Reading the provider market

audience: ai

The signer organism’s provider market is a public Collection<ProviderId, ProviderCard>. Any bonded peer can read it; providers write their own card; the organism’s committee scheduler selects from the collection when rotating committee membership. Consumers read the collection when they want to audit the committee’s current attestation mix independently of any specific outcome.

The ProviderCard shape

pub struct ProviderCard {
    pub provider_id:             UniqueId,
    pub schemes_supported:       Vec<SignatureScheme>,
    pub attestation_level:       AttestationLevel,
    /// Measurements digest for TDX-attested providers;
    /// long-term identity digest for software-only.
    pub attestation_digest:      UniqueId,
    pub capacity_per_second:     u32,
    pub fee_per_partial_wei:     u128,
    pub committed_at_unix_secs:  u64,
}

Every field is read-side; the write-side ACL is the provider’s ACL composed with the organism’s min_attestation_level floor. A provider below the floor cannot register.

The attestation ladder in full

The AttestationLevel enum is totally ordered; a level meets a floor iff its discriminant is ≥ the floor’s. The five levels, bottom to top:

Software

Declared identity only. The provider publishes a long-term software signing key; no hardware attestation. Consumers trust only the declaration, and if the software is compromised, all signatures it produced are suspect. Viable for staging or for signatures whose forgery cost is below the cost of attesting.

TdxLocal

TDX self-quote produced inside the guest. Peer committee members verify against declared Measurements. No external relying party. A consumer outside the committee cannot re-verify; the level’s value is to other committee members bonding against each other.

TdxRemote

TDX quote verified against Intel DCAP’s remote attestation service (or an equivalent operator-run service whose trust root is published). A consumer outside the committee can re-verify the quote and confirm the provider ran a Measurements-matched image. This is the canonical floor for production deployments.

TdxRaTlsBidirectional

Both sides of the attested channel produce and verify quotes at bond formation. A signer whose counterpart failed to produce a quote refuses to bond; a signer whose counterpart produced a non-matching quote refuses. Downgrade attacks become visible as bond-formation failures rather than as silently accepted non-attested counterparts.

TdxPlusReproducibleBuild

RA-TLS bidirectional plus the provider publishes the build recipe whose hash the Measurements attest to. A third party reproduces the build from source, verifies that the resulting binary hashes to the same Measurements, and confirms the committee is running the code the source describes. Without the reproducible root, the consumer trusts that the operator built the image honestly; with it, the consumer verifies the binary matches the source without running the operator’s image.

The eligibility check

Every provider’s card is evaluated against the organism’s deployment parameters. The check is ProviderCard::is_eligible(scheme, floor):

impl ProviderCard {
    pub fn is_eligible(
        &self,
        scheme: SignatureScheme,
        floor: AttestationLevel,
    ) -> bool {
        self.attestation_level.meets(floor)
            && self.schemes_supported.iter().any(|s| *s == scheme)
    }
}

Two conditions: the provider’s attestation level meets the floor, and the provider declares support for the scheme the organism commits to. A provider that wants to serve two schemes registers two entries in schemes_supported; a provider that wants to serve two floors in two separate deployments registers two cards with distinct provider ids.

Consumer-side selection

The consumer does not need to pick specific providers; the organism’s scheduler picks. But a consumer that cares about the attestation distribution reads the card collection and can:

  • Audit the mix. Count providers at each level. If the consumer’s floor is TdxRemote and only committee_size - 2 providers meet it, the consumer knows admission will succeed only when the 2-provider gap is not on the threshold boundary.
  • Rank by fee. A consumer that wants to estimate cost reads fee_per_partial_wei per card and forecasts end-to-end cost as threshold × mean(fee).
  • Track capacity. A consumer planning a burst reads capacity_per_second per card and computes whether the committee can absorb the peak.

None of these are required; the organism’s scheduler runs correctness-safe selection regardless. The collection exists because mosaik’s stigmergic-collection pattern (emergent coordination — pattern 1) works at this rung: public reads, consumer-side filtering, no central allocator.

Provider competition shape

Providers compete on three axes. All three fold into ProviderCard::card_digest; a change to any is a republish event observable through the collection.

  • Attestation level. Higher levels pull in more consumers (wider admission) at higher operational cost (reproducible builds require source-and- toolchain hygiene).
  • Capacity. A provider with higher capacity_per_second wins more committee slots in bursty windows; a provider with lower capacity runs cheaper.
  • Fee. fee_per_partial_wei is the per-partial- signature price the provider commits to. A provider charging above the committee median needs matching quality (higher attestation, lower tail latency, better availability); a provider charging at or below median gets routine allocation.

A reputation organism gating admission on ProviderCard quality (uptime, completed-requests ratio, attestation-challenge pass rate) is the closest kin to the web2 provider-reputation pattern. This chapter names the shape and stops; reputation organisms are specified once in ai/emergent-coordination.md — pattern 2.

Forward

Chapter 4 (wrapping) walks the provider side: how each attestation level is produced in practice — TDX quote, Intel DCAP verification, RA-TLS bidirectional channel, reproducible-build recipe.

Wrapping attestation surfaces

audience: ai

Every attestation level from provider-reads is produced the same way at the mosaik bond layer: the provider publishes evidence that another peer can verify before the bond forms. This chapter walks how each level is produced in practice, what the provider’s image does to ship it, and what the verifier re-checks.

Software — the null case

The provider’s attestation_digest is the blake3 digest of its long-term Ed25519 identity public key. The bond-formation handshake checks signatures produced by that key against the published digest. There is no hardware evidence; the Software level names that fact explicitly rather than pretending otherwise.

// Provider side.
let identity_sk = ed25519::SigningKey::from_bytes(&seed);
let identity_pk = identity_sk.verifying_key();
let attestation_digest = UniqueId::hash(identity_pk.as_bytes());

// Verifier side, inside the bond handshake.
let challenge = bond_challenge_bytes();
let sig = peer_sign(challenge);
assert!(identity_pk.verify(&challenge, &sig).is_ok());

Threat model: a key-leak compromises every signature the provider ever produced under that identity. A provider losing its key publishes a retirement marker; consumers downstream of the leaked provider’s signatures re-verify against a new identity.

TdxLocal — per-peer TDX quote

The provider runs inside a TDX guest whose Measurements are declared in the organism’s Config. At bond-formation, the provider generates a TDX quote binding the bond’s nonce and the peer’s identity into the quote’s report_data field.

// Inside the TDX guest, provider-side.
let report_data = blake3::Hasher::new()
    .update(b"signer-bond|")
    .update(peer_identity_pk.as_bytes())
    .update(&bond_nonce)
    .finalize();
let quote = mosaik::tee::tdx::generate_quote(&report_data);

// Peer verifies locally.
let quote = receive_quote_from_bond();
let td_info = mosaik::tee::tdx::parse_quote(&quote)?;
assert_eq!(td_info.mr_td, DECLARED_MR_TD);
assert_eq!(td_info.mr_config_id, DECLARED_MR_CONFIG_ID);
assert_eq!(
    td_info.report_data,
    expected_report_data(peer_identity_pk, &bond_nonce),
);

The verification is local — no round trip to Intel’s DCAP service. A peer verifying a TdxLocal quote re-computes the attestation check against Intel’s anchor certificates (shipped with the verifier image) and the organism’s declared Measurements.

Threat model: the TDX guest’s image is the trust anchor. An attacker with a zero-day against TDX defeats local verification; the TdxRemote level adds a DCAP round-trip that independent consumers rely on.

TdxRemote — DCAP-verified quote

Same generation path as TdxLocal. The verification path additionally routes the quote through Intel’s DCAP attestation service (or a declared equivalent):

let quote = receive_quote_from_bond();

// Local parse (same as TdxLocal).
let td_info = mosaik::tee::tdx::parse_quote(&quote)?;
assert_eq!(td_info.mr_td, DECLARED_MR_TD);

// Additional: DCAP round-trip.
let dcap = mosaik::tee::tdx::dcap::Client::new(
    DECLARED_DCAP_ROOT_URL,
);
let verdict = dcap.verify(&quote).await?;
assert!(matches!(verdict, dcap::Verdict::Ok));

A consumer outside the committee can re-verify an outcome’s aggregate by pulling the participating providers’ quotes from the organism’s stream of bond-time evidence and re-running the DCAP verification. This is the canonical production floor.

TdxRaTlsBidirectional — two-way attested channel

Both sides of the bond produce and verify quotes. Neither side accepts a non-attested counterpart; a committee member whose peer fails to produce a quote refuses to bond.

let server = mosaik::tee::tdx::ra_tls::server_config(
    DECLARED_MR_TD,
);
let client = mosaik::tee::tdx::ra_tls::client_config(
    DECLARED_MR_TD,
);

// Server side:
let (peer_quote, stream) = server.accept(tcp).await?;
let peer_td = parse_and_verify(&peer_quote)?;
assert_eq!(peer_td.mr_td, DECLARED_MR_TD);

// Client side:
let (peer_quote, stream) = client.connect(tcp, peer_spki).await?;
let peer_td = parse_and_verify(&peer_quote)?;
assert_eq!(peer_td.mr_td, DECLARED_MR_TD);

The bidirectional check matters at bond-formation. A downgrade attack — an adversary attempting to convince a matched-Measurements peer to accept a non-attested counterpart — surfaces as a connection refused at the RA-TLS handshake, not as a silently-accepted bond later caught by a second- line audit.

TdxPlusReproducibleBuild — source-to-binary anchor

The highest declared level. The provider additionally publishes:

  1. The build recipe — a declarative specification (Nix derivation, Bazel rule, Dockerfile checked-in under a pinned base image) that produces the binary whose Measurements the organism declared.
  2. A reproducible build artefact with a declared toolchain version. Anyone reproducing the build gets a binary with matching Measurements.

The consumer verifies:

// Offline verification by the consumer (or a third
// party auditing on the consumer's behalf).
let recipe = fetch(PROVIDER_RECIPE_URL).await?;
let recipe_digest = blake3::hash(&recipe);
assert_eq!(recipe_digest, DECLARED_RECIPE_DIGEST);

let build_output = rebuild_from_recipe(&recipe)?;
let mr_td = mosaik::tee::tdx::measurements_from_image(&build_output);
assert_eq!(mr_td, DECLARED_MR_TD);

This does not reduce trust to zero; the consumer still trusts the toolchain’s integrity and the declared anchor certificates. But the consumer no longer trusts the operator’s build pipeline — the binary the operator ships is the binary the source produces.

What the verifier never does

Across all levels above Software:

  • Never accept a quote whose Measurements do not match the declared set. A committee member that receives a non-matching quote treats the peer as absent, not as a fallback to a lower level.
  • Never ship the quote’s body into the public SignatureOutcome. The outcome carries a digest of the quote; the full quote is held by bonded peers and published to the organism’s evidence stream where consumers can pull it for audit.
  • Never re-use a quote across bonds. The bond nonce is fresh per bond; a replayed quote is an attack and rejected at the verifier.

Forward

Chapter 5 (signing) walks the request flow: how an admitted request enters the committee, how each provider produces a partial signature, and how partial sigs reach the committee-internal aggregator.

Partial-signing in the committee

audience: ai

This chapter walks what happens inside the signer committee when a SignatureRequest arrives: how the committee admits the request, how each provider produces a partial signature, and how partial sigs converge toward the aggregate. The committee-internal aggregation and the public commit live in aggregation.

The request pipeline

  requester                     committee                       verifier
      │                              │                              │
      │  SignatureRequest            │                              │
      │  (message_digest, scheme)    │                              │
      │─────────────────────────────>│                              │
      │                              │                              │
      │                              │   partial_sig(member i)      │
      │                              │ ◄──────── × committee_size   │
      │                              │                              │
      │                              │   aggregate (off-stream)     │
      │                              │ ──────────────────────────── │
      │                              │                              │
      │         SignatureOutcome     │                              │
      │<─────────────────────────────│                              │
      │  signature_digest,           │                              │
      │  participating_providers,    │                              │
      │  aggregate_attestation_level │                              │
      │                              │                              │
      │                              │   signature_bytes (sealed)   │
      │                              │ ─────────────────────────────>

Request admission

A SignatureRequest is admitted iff:

  1. ACL. The requester’s ticket composes cleanly with the organism’s TicketValidator. The check is the same mosaik primitive every other organism uses; nothing signer-specific.
  2. Scheme match. req.scheme equals Config.scheme. A request for an unsupported scheme is rejected at the stream ACL; it never reaches the committee.
  3. Body size. The side-channel body (delivered alongside the request digest via the operator- declared sealed channel) is ≤ M::MAX_BODY_BYTES.
  4. Deadline. req.deadline_unix_secs is in the future. Late requests are dropped rather than queued past their deadline.

Admission is cheap; the expensive work is the per-member partial-signing round below.

Per-member partial signing

Each committee member, on admitting the request, runs the scheme-specific partial-sign function:

// Inside the provider's TDX guest (for any
// attestation level above Software).
pub fn partial_sign<M: SignableMessage>(
    req:       &SignatureRequest<M>,
    body:      &[u8],                      // from sealed channel
    share_sk:  &SchemeSecretShare,
) -> PartialSignature {
    assert_eq!(UniqueId::hash(body), req.message_digest);
    match req.scheme {
        SignatureScheme::BlsAggregateG1 =>
            bls::partial_sign_g1(body, share_sk),
        SignatureScheme::BlsAggregateG2 =>
            bls::partial_sign_g2(body, share_sk),
        SignatureScheme::FrostSchnorrSecp256k1 =>
            frost_schnorr::partial_sign_secp256k1(
                body, share_sk, &current_nonce_commit(),
            ),
        SignatureScheme::FrostSchnorrEd25519 =>
            frost_schnorr::partial_sign_ed25519(
                body, share_sk, &current_nonce_commit(),
            ),
        SignatureScheme::FrostEcdsaSecp256k1 =>
            frost_ecdsa::partial_sign(
                body, share_sk, &current_nonce_commit(),
            ),
        SignatureScheme::LagrangeBls =>
            lagrange::partial_sign(body, share_sk),
    }
}

Two protocol families, one shape in the book. The member’s result is a PartialSignature committed to a committee-internal stream (not the public surface); aggregation runs off that stream.

Non-interactive vs. interactive schemes

The SignatureScheme::is_non_interactive() predicate separates the two families:

  • Non-interactive — BLS12-381 (both curves) and Shamir-Lagrange. A partial signature is self-contained; the committee aggregator can combine partials at any time in any order once the threshold is reached.

  • Interactive — FROST variants (Schnorr and ECDSA). Partial signatures reference a nonce commit the committee must run one round ahead of time. A missing nonce commit forces a retry, which the committee amortises across a window of upcoming requests.

The organism’s committee ships a nonce-commit rotation loop iff Config.scheme.is_non_interactive() is false. For BLS deployments the loop is absent and the commit bandwidth is zero.

if !Config::<M>::scheme(&cfg).is_non_interactive() {
    spawn_nonce_commit_rotator(&committee_handle);
}

Partial-sig visibility

The committee-internal stream carrying PartialSignatures is not publicly readable. Its ACL admits only bonded committee members. Reasons:

  • Partial-sig forgery window. A partial signature tied to a request id is meaningful only to the aggregator; leaking it early lets a byzantine aggregator claim the signature without running the full threshold. Restricting the audience to current committee members bounds the attack surface.
  • Cross-committee correlation. A provider that serves multiple signer deployments could leak one deployment’s partial sigs into another’s aggregator. The ACL composition pins each deployment’s committee to its own stream.

The publicly readable artefact from this rung is the SignatureOutcome committed in aggregation; partial sigs are committee-internal by design.

Member failure and threshold slack

The threshold is t-of-n; the committee tolerates n − t absent members per request. A request with fewer than t partial sigs at the deadline commits no outcome. The committee emits a RequestTimedOut entry (with the request id and the count achieved) so the requester can resubmit or escalate.

Non-adversarial absence — a committee member restarting, a transient network fault — resolves at the next cadence without operator intervention. Persistent absence triggers a committee rotation (sustainability).

Determinism

The partial-sign function is deterministic given (body, share_sk) for non-interactive schemes and deterministic given (body, share_sk, nonce_commit) for interactive schemes. Two honest providers running the same image against the same share produce the same partial signature. Aggregators treat a non- matching partial from a non-interactive provider as a byzantine fault and exclude the provider from the round.

Forward

Chapter 6 (aggregation) walks what happens after t partial sigs are in hand: the aggregate combine, the SignatureOutcome commit, and the sealed delivery of the signature bytes back to the requester.

Aggregate and publish

audience: ai

With t partial signatures in the committee’s internal stream, the aggregator combines them into the final threshold signature, commits a public SignatureOutcome, and delivers the signature bytes to the requester through the sealed side channel declared at setup. This chapter specifies all three steps and the shape consumers gate admission against.

Aggregate

The aggregator is any committee member — the protocol does not assign a fixed leader. Whichever member first observes t partial sigs for a request runs the scheme-specific combine:

pub fn aggregate<M: SignableMessage>(
    cfg:       &Config<'_, M>,
    partials:  &[PartialSignature],
) -> Result<AggregateSignature, AggregateError> {
    assert!(partials.len() >= cfg.threshold as usize);
    match cfg.scheme {
        SignatureScheme::BlsAggregateG1 =>
            bls::aggregate_g1(partials),
        SignatureScheme::BlsAggregateG2 =>
            bls::aggregate_g2(partials),
        SignatureScheme::FrostSchnorrSecp256k1 =>
            frost_schnorr::combine_secp256k1(partials),
        SignatureScheme::FrostSchnorrEd25519 =>
            frost_schnorr::combine_ed25519(partials),
        SignatureScheme::FrostEcdsaSecp256k1 =>
            frost_ecdsa::combine(partials),
        SignatureScheme::LagrangeBls =>
            lagrange::combine(partials),
    }
}

Under non-adversarial assumptions the combine is deterministic and verifies against the committee’s published aggregate public key (Config.committee_pk_digest). A failed combine — malformed partials, mismatched nonce commits, a byzantine signer producing garbage — is logged and the aggregator runs the combine with a different subset of partials if the count allows.

The public SignatureOutcome

Once a verifying aggregate is in hand, the aggregator commits a SignatureOutcome on the organism’s outcome collection. The outcome carries only metadata; the signature bytes themselves go through the sealed side channel.

pub struct SignatureOutcome<M: SignableMessage> {
    pub request_id:                  UniqueId,
    pub signature_digest:            UniqueId,
    pub participating_providers:     Vec<UniqueId>,
    pub aggregate_attestation_level: AttestationLevel,
    pub committed_at_unix_secs:      u64,
    pub _phantom:                    PhantomData<M>,
}

Four fields a consumer acts on:

  • request_id — joins the outcome back to the requester’s earlier submission.
  • signature_digest — blake3 of the aggregate signature bytes. Consumers pulling the sealed-channel payload verify the delivered signature hashes to this digest.
  • participating_providers — the t providers whose partials combined into the aggregate. Consumers can cross-reference against the ProviderCard collection (provider-reads).
  • aggregate_attestation_level — the minimum attestation level across the participating providers. This is the field the consumer’s TicketValidator gates against (binding).

The minimum — not the majority, not the declared-on-card — is what the outcome carries. A request served by four TdxRemote providers and one TdxLocal provider yields an outcome with aggregate_attestation_level = TdxLocal. A consumer whose floor is TdxRemote does not admit the outcome; the signature is still verifiable, just not at the consumer’s declared trust level.

The sealed side channel

The actual signature bytes are too big for the public commit — a BLS aggregate is 48 or 96 bytes, a FROST Schnorr sig is 64, and every outcome’s bytes would clog the public Collection for audit-only consumers. They travel through the organism’s sealed side channel:

  committee aggregator
        │
        │  SealedEnvelope {
        │    recipient_pk: requester_identity_pk,
        │    ciphertext:   encrypt_to(signature_bytes,
        │                             requester_identity_pk),
        │    request_id:   <matches public outcome>,
        │  }
        │
        ▼
   sealed channel
        │
        │  (only the requester's key can open)
        ▼
  requester
        │
        │  let sig = decrypt(ciphertext);
        │  assert_eq!(blake3::hash(&sig), outcome.signature_digest);

The sealed-channel cryptography is standard X25519 + ChaCha20-Poly1305 (the same primitive pattern the compute-bridge uses for encrypted SSH receipts). The requester’s identity key binds to their coalition’s stable id; the committee has no access to the signature bytes after delivery.

Determinism and replay

The aggregate signature is scheme-deterministic for non-interactive schemes and scheme-deterministic-given-nonce-commits for interactive schemes. Two honest aggregators running on the same partials (same subset, same order where order matters) produce the same aggregate.

Replay protection: the (request_id, aggregate_attestation_level) tuple in the outcome is unique per request, and the organism’s state machine rejects a second commit for the same request_id. A byzantine aggregator attempting to replay a partial set from a prior request has its commit rejected by the committee’s Raft log.

Failure modes

  • AggregationFailure. Partial sigs failed to combine (byzantine signer, corrupted share). The aggregator commits a RequestFailed entry; consumers observe the public commit and resubmit.
  • SideChannelDeliveryFailure. Aggregate combined, outcome committed, but the sealed envelope did not reach the requester. The requester reads the signature_digest from the public outcome, submits a ResendDelivery request, and the aggregator re-seals and resends. This is a liveness concern, not a safety one — the signature already exists.
  • OutcomeSignerMismatch. A consumer verifying the aggregate against the committee’s published public key gets a mismatch. This is the forgery alarm: either the published key is wrong (operator error or compromise), or the committee is byzantine. The consumer halts, unpins the organism in its TicketValidator, and waits for a rotation.

Forward

Chapter 7 (sustainability) walks what happens when the committee rotates — key refresh, committee-member replacement, retirement markers, and the multi-operator fleet shape that lets consumers fail over when a specific signer-δ deployment retires.

Committee rotation, key refresh, successor chain

audience: ai

The signer-δ committee does not stay fixed. Key material rotates on a declared cadence; committee membership changes as providers register, retire, or degrade; consumers follow the rotation through the organism’s retirement chain without re-publishing their own CoalitionConfig. This chapter walks all four loops: proactive key refresh, committee-membership rotation, retirement markers, and multi-operator fleets.

Part II’s four worked examples end here. Every mosaik surface the book’s thesis names has been exercised across searcher-α, bridge-β, oracle-γ, and signer-δ.

Proactive key refresh

The committee’s DKG aggregate public key is pinned into Config.committee_pk_digest. A rotation produces a new DKG-generated key; every committee member resharing its long-term key share to the new dealing produces a new committee_pk_digest and a new organism id.

The refresh shape:

  window 0: committee runs DKG round 0
    │   publishes Config_v0 with committee_pk_digest = PK_0
    │   signer-δ.v0 stable_id = S_0
    │
  window 1: committee runs DKG round 1 alongside round 0
    │   both active; outcomes from either verify
    │   against their respective published pk
    │   publishes Config_v1 with committee_pk_digest = PK_1
    │   signer-δ.v1 stable_id = S_1
    │   retirement marker on v0:
    │     reason = Rotation
    │     replacement = OrganismRef { stable_id: S_1, content_hash: v1_hash }
    │
  window 2: v0 goes read-only for grace period
    │   new requests go to v1 only
    │
  window 3: v0 decommissioned; v1 continues

Consumers that pinned v0’s stable id and content hash follow the retirement marker’s replacement pointer to rebind. Consumers that pinned only the stable id continue against v1 without any consumer-side change — the committee published new keys, the retirement chain records it, the consumer’s TicketValidator re-composes on next read.

Why not lazy key refresh

Leaving the key in place until compromise is detected is the other design choice. This organism does not take it: proactive refresh is a precondition for the TdxPlusReproducibleBuild level (every refresh produces a fresh DKG log that a third party can audit against the reproducible source) and it bounds the damage window from a hypothetical share extraction. Real deployments typically refresh on a 7- to 30-day cadence; the cadence itself is published in Config.content (not modelled in this example crate, but a clean extension).

Committee-membership rotation

Committee membership is a separate rotation axis from key refresh. A provider whose capacity or attestation level changes — hardware refresh, attestation-service endpoint change, TDX firmware patch — republishes its ProviderCard. A provider retiring emits its own retirement marker and drops out of the next DKG round’s dealing set.

use coalition::{ComponentRef, RetirementMarker, RetirementInstant};

// Provider-side retirement commit.
let marker = RetirementMarker::rotation(
    RetirementInstant::AtTimestamp(now_unix_ms()),
    successor_provider_ref,
);

The signer-δ operator scans provider retirement markers at each rotation window and includes the successor provider in the next committee. Consumers that cared about a specific provider unpin its provider id from their audit set; consumers that filtered by attestation level never noticed the swap.

Variable attestation mix across rotations

The variance is the point. A rotation may raise or lower the committee’s attestation mix:

  • Raising. A signer-δ operator hardening posture moves the committee toward more TdxRaTlsBidirectional and TdxPlusReproducibleBuild members. Consumers whose floor is at or below the new mix see their admission broaden (more outcomes meet their floor).
  • Lowering. A signer-δ operator under cost pressure rotates in TdxLocal or Software members. Consumers whose floor is at or above the new mix see their admission narrow; the outcomes whose aggregate_attestation_level falls below the floor are simply not admitted.

The consumer’s TicketValidator handles both cases without any consumer-side code change. The floor is the floor.

Retirement markers

The substrate’s retirement primitive handles every shutdown path. Four shapes relevant to signer-δ:

// Planned rotation with successor.
RetirementMarker::rotation(
    RetirementInstant::AtTimestamp(effective_at),
    successor_organism_ref,
);

// Permanent retirement without successor.
RetirementMarker::retired(
    RetirementInstant::AtTimestamp(effective_at),
);

// Operator exit — non-compulsion anchor.
RetirementMarker::operator_exit(
    RetirementInstant::AtTimestamp(effective_at),
);

// Emergency (share extraction, TDX zero-day, etc.).
// Same shape; `reason = Emergency`. Pair with an
// out-of-band security advisory.

Consumers observe retirement markers on the signer’s public outcome collection. A retirement marker is the last commit on the stream; after it, no new outcomes are admitted. Consumers whose bond to the organism outlives the marker see ConnectTimeout on next subscribe.

Multi-operator fleets

The signer’s trust model admits independent operators running the same image with the same declared Measurements. Two operators running identical deployments land identical committee_pk_digest under identical DKG seeds (and distinct organism_ids because the instance names differ).

Fleet shape:

pub const SIGNER_DELTA_OP1: CoalitionConfig<'static> = /* signer-δ-op1 */;
pub const SIGNER_DELTA_OP2: CoalitionConfig<'static> = /* signer-δ-op2 */;
pub const SIGNER_DELTA_OP3: CoalitionConfig<'static> = /* signer-δ-op3 */;

// Consumer subscribes to all three; applies
// consumer-side aggregation (first to respond,
// majority-matching, etc.).

A consumer wanting redundancy submits to the fleet; the first respondent’s signature is taken as authoritative, and a consumer sufficiently paranoid to cross-check runs all three and requires byte-identical signature bytes (works for non-interactive schemes; interactive schemes produce different-but-valid signatures across operators’ DKG rounds).

This is the answer to operator failure, collusion resistance (modulo the shared image), and geographic diversity. The substrate’s non- compulsion property holds: operators join or leave the fleet voluntarily, and no instance compels any other.

Chronicle for the rotation log

For operators who want a tamper-evident record of every rotation and retirement, signer-δ may optionally ship the Chronicle basic service from chapter 7 onward. The Chronicle records every coalition-level event — committee rotation, retirement marker, key refresh, ACL bump — without recording every signature (the outcome collection is already a public audit of those).

Operator exit

At any time, the signer-δ operator can emit an OperatorExit retirement marker and stop running the binary. Consumers observing the marker fail over to another operator in the fleet; consumers without a fleet see the signatures stop. Nothing in the substrate keeps the operator running.

The trust model is strong because the operator can leave: the attestation floor is an admission criterion on the consumer side, the operator’s exit is the substrate’s non-compulsion anchor, and the two together mean a consumer never depends on a single operator being both honest and forced to stay online.

What Part II ends with

Across four parallel examples:

  • searcher-α (web3) — an AI searcher binds to a block-building lattice and a Compute market, submits sealed bundles, and grows a reputation surface around itself.
  • bridge-β (web2) — a compute-bridge operator wraps four cloud backends behind one TDX- attested provider identity and competes on the coordination-market rate.
  • oracle-γ — a standalone organism publishes one Stream<PriceTick> per token pair with the whole trust model anchored on a declared TDX Measurements set.
  • signer-δ — a generic threshold-signature organism hosts a market of providers at varying attestation levels; consumers gate admission on aggregate attestation.

The four examples together walk consumer, provider, publisher, and committee-organism roles — every primitive rung the book’s thesis names.

Cross-references

What a coalition gives you

audience: integrators

A coalition is a single handshake token binding an agent to multiple members of the mosaik universe at once: block-building lattices, standalone organisms (oracles, attestation fabrics, identity substrates, analytics pipelines, …), composite organisms (cross-member organisms), and the coalition’s optional basic services (Atlas, Almanac, Chronicle, Compute, Randomness — whichever are shipped). Compile one CoalitionConfig and obtain typed handles on every member, every basic service, and every organism the coalition references, from one Arc<Network>.

If you already bind to one lattice via a LatticeConfig, or to one standalone organism via its Config, a coalition does not change any of that. It adds:

  • A single reference to a set of members the operator has chosen to yoke together (e.g. every chain in a superchain stack; every oracle feed in a region; a set of lattices plus a shared attestation fabric).
  • Optional composite organisms: cross-member organisms that aggregate, route, or attest across the members in the coalition. Composite organisms are not coalition-scoped; the same organism may be referenced by many coalitions.
  • Optional basic services: up to five well-known shapes — Atlas (directory), Almanac (clock beacon), Chronicle (audit log), Compute (scheduler and registry for image-hash-identified workloads), Randomness (scheduler and registry for beacon rounds; beacon producers compete to supply).
  • An optional coalition-scoped ticket issuer. Components choose whether to recognise its tickets; nothing is required to.
  • No loss of identity. Every member’s GroupId, every PeerId, every StreamId you already use stays byte-for-byte the same under routine operational rotations (TDX Measurements bumps, ACL rotations). A coalition references members; it does not re-derive them.

An agent binding to one member only does not need a CoalitionConfig; bind directly to that member’s Config (for a block-building lattice, see the builder integrators overview; for a standalone organism, see its own crate docs). The coalition layer is additive, not a replacement.

When you want a CoalitionConfig

Four common cases.

Cross-chain searcher

You bid on bundles across three block-building lattices and want one handshake token that carries all three LatticeConfigs, their TDX Measurements, and any referenced organisms (e.g. a shared ledger that aggregates your refunds across chains).

Hold one CoalitionConfig, open three offer::Offer<Bundle>::bid handles, one ledger::Shared<Refund>::read. See the quickstart.

Multi-chain wallet

You submit intents on several lattices and need refund attestations from each. If the coalition references a shared-ledger organism, you can read one aggregated feed instead of polling per-lattice tally::Refunds.

Cross-domain agent

Your agent consumes outputs from a mix of members — say, two block-building lattices, an oracle grid, and an attestation aggregator — and you want one compile-time token that pins the full set. A CoalitionConfig lets you hold one handshake instead of four.

Composite-organism or module consumer

You are an analytics, routing, or dashboard service that reads an intent router, a shared ledger, a cross-chain oracle aggregator, or the coalition’s Atlas. Without a CoalitionConfig, you would re-derive each fingerprint yourself; with it, you compile one struct.

When you do not need a CoalitionConfig

  • You bind to one member only.
  • You are an integrator testing a standalone organism whose operator has given you its OrganismConfig directly.
  • You are an integrator testing a composite organism whose operator has given you its OrganismConfig directly.
  • You only read a public collection whose StoreId you already have; coalitions are compile-time ergonomics.

What the operator gives you

When a coalition operator hands you a handshake, you should receive:

  • The CoalitionConfig struct (or its serialised fingerprint).
  • The included LatticeConfigs — either inline or by reference to each lattice operator’s published handshake.
  • The included standalone-organism references — each with role name, stable id, optional content hash, and a pointer to that organism’s own handshake.
  • The included composite organisms — each with its OrganismConfig and a pointer to the organism operator’s handshake.
  • The included modules — each an OrganismConfig with the shape documented in basic services.
  • The ticket-issuer root if the coalition ships one.
  • TDX Measurements for every TDX-gated organism (standalone, composite, or module) the coalition commissioned.
  • Endpoint hints for at least one initial peer on the shared universe, if your agent is cold-starting.

See What you need from the coalition operator for the full checklist.

What you compile in

use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;
use coalition::CoalitionConfig;

const ETH_SUPERCHAIN: CoalitionConfig<'static> = /* pasted from operator release notes */;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let network = Arc::new(Network::new(UNIVERSE).await?);

    // Pick handles you need — any lattice organism, any
    // standalone organism, any composite organism, any
    // module.
    let eth_bid = offer::Offer::<Bundle>::bid(
        &network, &ETH_SUPERCHAIN.lattices[0].offer,
    ).await?;
    let uni_bid = offer::Offer::<Bundle>::bid(
        &network, &ETH_SUPERCHAIN.lattices[1].offer,
    ).await?;
    // A standalone organism the coalition references — here, an
    // attestation aggregator with its own Config.
    let attest = attest::Aggregator::<Quote>::read(
        &network, ETH_SUPERCHAIN.organisms[0].config(),
    ).await?;
    // A composite organism — same shape, one rung up.
    let ledger = ledger::Shared::<Refund>::read(
        &network, ETH_SUPERCHAIN.organisms[1].config(),
    ).await?;
    // A module — the coalition's Atlas, if shipped.
    let atlas  = atlas::Atlas::<MemberCard>::read(
        &network, ETH_SUPERCHAIN.atlas().unwrap(),
    ).await?;
    // ... use them.
    Ok(())
}

ETH_SUPERCHAIN.atlas() returns the Atlas module’s Config if the coalition ships one. The same helper exists for almanac() and chronicle(). A coalition that does not ship a given module returns None.

No additional plumbing. UNIVERSE is the same constant every lattice and zipnet deployment uses.

What can go wrong

  • ConnectTimeout. The CoalitionConfig you compiled in does not match what the operator is running. Recompile against the current release notes.
  • Ticket missing on a specific member. Your per- member admission ticket was not issued or was revoked. Per-member operators issue their own tickets; the coalition operator does not. Contact the per-member operator.
  • An organism down. A committee lost majority. Other members continue; the affected component’s next commit is delayed.
  • Module helper returns None. The coalition does not ship that module. Drop the dependency or request the module be added.

Cross-references

Quickstart — bind many members from one agent

audience: integrators

This quickstart stands up an agent that submits and reads across three block-building lattices, one standalone attestation organism, one composite organism, and one module (the coalition’s Atlas) — all bound through a single CoalitionConfig. It assumes familiarity with the builder integrators quickstart when the coalition includes block-building lattices; the coalition layer extends that pattern rather than replacing it.

If the coalition contains no lattices (for example, a composition of oracle organisms plus a cross-oracle composite organism), the same pattern applies with different crates on the right-hand side of each handle.

What you need before you start

  • A CoalitionConfig from the coalition operator (struct definition, or a serialised fingerprint you copy into your crate).
  • A LatticeConfig per referenced lattice (inline in the CoalitionConfig the operator published, or pulled from each lattice operator’s handshake page).
  • An OrganismRef per referenced organism (role name + stable id + optional content hash + pointer to the organism’s own handshake). Both standalone and composite organisms are referenced this way.
  • A ticket from each per-member operator you intend to write to. Per-member admission is per-member; the coalition operator does not issue per-member tickets.
  • A ticket from each composite-organism or module operator whose write-side primitive you intend to use. Usually none: most composite organisms and modules are read-only for external integrators.
  • Your TDX image (if any member or service you write to requires attested client admission).

Step 1 — declare the CoalitionConfig in your crate

Paste the operator’s published CoalitionConfig definition, or import it from the operator’s handshake crate if they publish one:

use builder::LatticeConfig;
use coalition::{CoalitionConfig, OrganismRef};

// Exactly the bytes the operator publishes.
const ETH_MAINNET:      LatticeConfig<'static> = /* from ethereum.mainnet operator */;
const UNICHAIN_MAINNET: LatticeConfig<'static> = /* from unichain.mainnet operator */;
const BASE_MAINNET:     LatticeConfig<'static> = /* from base.mainnet operator */;

// A standalone organism the coalition references — here,
// an attestation aggregator with its own stable id.
const ATTEST_AGG: OrganismRef<'static> = OrganismRef {
    role: "attest",
    stable_id: /* published by the attest-aggregator operator */,
    content_hash: None,
};

// Two composite organisms the coalition references — an
// intent router and a shared ledger.
const INTENTS_CONF: OrganismRef<'static> = OrganismRef {
    role: "intents",
    stable_id: /* from the intents operator */,
    content_hash: None,
};
const LEDGER_CONF:  OrganismRef<'static> = OrganismRef {
    role: "ledger",
    stable_id: /* from the ledger operator */,
    content_hash: None,
};

pub const ETH_SUPERCHAIN: CoalitionConfig<'static> = CoalitionConfig {
    name: "ethereum.superchain",
    lattices:  &[ETH_MAINNET, UNICHAIN_MAINNET, BASE_MAINNET],
    organisms: &[ATTEST_AGG, INTENTS_CONF, LEDGER_CONF],
    ticket_issuer: None,
};

For a coalition-agnostic library, take &'static CoalitionConfig<'static> as a constructor argument and let the binary crate pick the constant.

Step 2 — bring up the network handle

Same UNIVERSE as every other mosaik service:

use std::sync::Arc;
use mosaik::Network;
use builder::UNIVERSE;

let network = Arc::new(Network::new(UNIVERSE).await?);

One Arc<Network> per agent regardless of how many members, organisms, or modules are bound.

Step 3 — bind the lattice handles you need

Indexes into lattices[] match the order in the CoalitionConfig. A cross-chain searcher that bids on all three:

use offer::Offer;

let eth_bid  = Offer::<Bundle>::bid (&network, &ETH_SUPERCHAIN.lattices[0].offer).await?;
let uni_bid  = Offer::<Bundle>::bid (&network, &ETH_SUPERCHAIN.lattices[1].offer).await?;
let base_bid = Offer::<Bundle>::bid (&network, &ETH_SUPERCHAIN.lattices[2].offer).await?;

let eth_wins  = Offer::<Bundle>::outcomes(&network, &ETH_SUPERCHAIN.lattices[0].offer).await?;
let uni_wins  = Offer::<Bundle>::outcomes(&network, &ETH_SUPERCHAIN.lattices[1].offer).await?;
let base_wins = Offer::<Bundle>::outcomes(&network, &ETH_SUPERCHAIN.lattices[2].offer).await?;

Keep handles in scope while needed; drop them when done. Each handle carries its own subscriptions and is cheap atop the shared Network.

Step 4 — bind the organism handles you need

Each OrganismRef carries the stable id; the concrete organism crate gives you the typed constructor. Standalone and composite organisms share the same reference shape:

use attest::Aggregator;

let attest = Aggregator::<Quote>::read(
    &network, ETH_SUPERCHAIN.organisms[0].config(),
).await?;

OrganismRef::config() resolves to the organism’s Config — either because the coalition operator embeds the full Config struct in their published CoalitionConfig, or because the organism crate ships a helper that rebuilds the Config from the published stable id and known role constants. Either way, the concrete organism crate is what gives you the typed handle.

Step 5 — bind the modules you want

Modules are coalition-scoped organisms with well-known shapes. CoalitionConfig exposes helpers:

use atlas::Atlas;
use almanac::Almanac;

// The Atlas lists every member in the coalition with operator metadata.
if let Some(atlas_cfg) = ETH_SUPERCHAIN.atlas() {
    let atlas = Atlas::<MemberCard>::read(&network, atlas_cfg).await?;
    // Use the atlas as your canonical "what's in this coalition" reference.
}

// The Almanac is a shared tick beacon for timing correlations.
if let Some(almanac_cfg) = ETH_SUPERCHAIN.almanac() {
    let almanac = Almanac::<AlmanacTick>::read(&network, almanac_cfg).await?;
    // Use almanac ticks as the time axis for cross-member commits.
    // Each tick's `observed_at` is a Vec<(MemberId, SystemTime)>;
    // compute median or bracket yourself.
}

A coalition may ship zero, one, two, three, or all four modules. Always check the helper’s Option return; do not assume presence.

Step 6 — bind the composite-organism handles you need

The shared ledger is typical for a searcher seeking aggregated refund attribution:

use ledger::Shared;

let refunds = Shared::<Refund>::read(
    &network, ETH_SUPERCHAIN.organisms[2].config(),
).await?;

tokio::spawn(async move {
    while let Some(r) = refunds.next().await {
        // Each entry carries (origin_member, slot, share, evidence).
        handle_refund(r);
    }
});

Step 7 — submit paired bundles

Cross-chain bundles are a searcher-level problem. The coalition layer surfaces the handles; reconciliation logic is the integrator’s responsibility.

async fn submit_paired_bundle(
    eth_bid: &Offer<Bundle>::Bid,
    uni_bid: &Offer<Bundle>::Bid,
    sell_on_eth: Bundle,
    buy_on_uni:  Bundle,
) -> anyhow::Result<()> {
    let eth_ack = eth_bid.send(sell_on_eth).await?;
    let uni_ack = uni_bid.send(buy_on_uni ).await?;
    // Reconcile: if only one leg commits, post-bond collateral or
    // on-chain HTLC logic applies. The coalition layer does NOT
    // provide cross-member atomicity. See
    // /contributors/atomicity.md.
    Ok(())
}

A paired-bundle correlator joining AuctionOutcome[L1, S] to AuctionOutcome[L2, S'] is the most common in-agent utility. Compute it in-memory as in builder’s Shape 1, or rely on a referenced intents composite organism if one exists.

Step 8 — read the aggregated result

With a shared-ledger composite organism, a single subscription surfaces refunds originating from any of the coalition’s lattices.

while let Some(entry) = refunds.next().await {
    tracing::info!(
        origin = %entry.origin_member,
        slot   = entry.slot,
        share  = %entry.share,
        "refund attributed",
    );
}

Without a shared-ledger composite organism, open three per-lattice tally::Tally::<Attribution>::read handles and join in memory. Both paths are valid; the composite organism is a shared precomputation.

What to do when things go wrong

  • ConnectTimeout on a lattice or organism handle. The per-member Config does not match what the member’s operator is running. Recompile against that operator’s latest handshake.
  • ConnectTimeout on an organism or module handle. The OrganismConfig does not match, or the committee is down and has not yet published peers on the universe, or the organism has retired (check for a RetirementMarker on its public stream) and the coalition operator should have sent an updated CoalitionConfig.
  • Admission denied on a write-side stream. Ticket missing or expired. Contact the per-member operator, not the coalition operator.
  • Module helper returns None. The coalition does not ship that module. See contributor basic services for the spec if proposing addition.

Cross-references

What you need from the coalition operator

audience: integrators

Before compiling a CoalitionConfig into an agent, the integrator requires a short item list from the coalition operator plus a pair of sanity checks. This page is the checklist.

The seven items

  1. The CoalitionConfig definition. Either a Rust const declaration pasted into the integrator crate, or a serialised fingerprint (hex of coalition_id()) paired with the integrator’s own copy of the struct definition.

  2. Every included LatticeConfig. Typically pulled by reference from each lattice operator’s handshake page. The coalition operator should publish a per-coalition table listing the referenced lattices and a link to each lattice operator’s release notes.

  3. Every included OrganismRef. For each organism the coalition composes — standalone or composite — the coalition operator publishes the role name, the organism’s stable id, the optional content hash if pinned, and a link to that organism’s own handshake page. Organisms are coalition-independent; each carries a link to its own operator’s handshake page.

  4. Every shipped module’s OrganismConfig. Atlas, Almanac, Chronicle — whichever the coalition ships. Modules not shipped are stated explicitly; silence is ambiguous.

  5. TDX Measurements for every TDX-gated unit the coalition operator commissions — modules and any organisms they run. (Per-member TDX Measurements come from the per-member operators; the coalition operator re-publishes for convenience.)

  6. At least one initial peer hint for the shared universe (cold-start bootstrap). Typically the same hint every mosaik service uses; re-published for convenience.

  7. A change channel. The mechanism through which the coalition operator notifies of a referenced member’s stable-id bump or a referenced organism’s Config change.

Coalition operators do not issue per-member tickets; those come from per-member operators. A coalition may publish its own optional ticket issuer; components and integrators choose whether to recognise it.

Verification

Perform two sanity checks once the items above are in hand.

Fingerprint round-trip

Compile the pasted CoalitionConfig. Call coalition_id() on it. Compare to the operator’s published fingerprint. Both must match byte-for-byte. A mismatch means the struct definition drifted or the serialiser differs; do not proceed until the mismatch resolves.

Member reference cross-check

For each referenced LatticeConfig, call stable_id() and compare to the lattice operator’s published stable id. For each referenced organism, compare the OrganismRef stable id (and content hash, if pinned) to the organism operator’s published one. A mismatch means the coalition operator’s copy drifted from the per- member operator’s. Request an updated CoalitionConfig.

Trust

Nothing in the coalition operator’s handshake is cryptographically authoritative: a coalition fingerprint names a composition, it does not sign it. The checks above suffice because the identity work is done at the per- member rung. The coalition layer stitches known fingerprints together and adds a small catalog of modules.

Cross-references

Binding to an organism

audience: integrators

An organism referenced by a coalition can be a standalone organism (living directly on the universe) or a composite organism whose public surface spans multiple members — some combination of block-building lattices and standalone organisms. Binding is the same in every case — Organism::<D>::verb(&network, &Config) — with two small differences in what the operator owes the integrator and in failure-mode reasoning when the organism is composite.

The same reasoning applies to a coalition’s modules (Atlas, Almanac, Chronicle, Compute, Randomness) — each is a coalition-scoped organism with a well-known shape.

One handle per verb

Each organism exposes one or two public primitives. A read-only integrator typically needs exactly one handle; a write-side integrator a second. Typical shapes:

// Read-only: subscribe to the organism's output.
let intents = intents::Router::<Intent>::routed(&network, &INTENTS_CONF).await?;

// Write-side (if the organism publishes a write stream):
let publish = intents::Router::<Intent>::publish(&network, &INTENTS_CONF).await?;

Verb names come from the organism’s own crate docs, following the same convention as every organism (Offer::bid, Tally::read, Zipnet::submit, Aggregator::read, Atlas::read).

What the organism operator owes you

An organism operator (who may coincide with the coalition operator) is responsible for:

  • The OrganismConfig fingerprint, publishable and byte-for-byte compilable.
  • The ordered list of spanned member references the organism depends on — lattices, standalone organisms, or any mix. Cross-check each against the corresponding per-member operator’s publication.
  • TDX Measurements if the organism is TDX-gated.
  • The organism’s state-machine version / signature. A bump surfaces as ConnectTimeout on compiled handles; the change channel warns ahead.
  • A failure-mode statement. Whether a stall in spanned member A causes a commit with partial evidence or an event stall. Documented in the crate’s composition-hooks page.
  • A retirement commitment. Before shutting the committee down, the organism emits a RetirementMarker on its public stream pointing at a replacement (if any). Watch for it rather than timing out blindly.

Failure-mode reasoning for composite-organism consumers

Three properties to internalise before reading a composite organism.

The composite commit lags the upstream commits

A composite organism’s (member_id, slot) commit is observable only after the underlying member commits are observable, plus one Raft round inside the organism’s committee. Latency-sensitive consumers read the upstream member surfaces directly and use the composite organism only for the aggregated view.

Partial evidence is a valid composite-organism commit

Depending on the organism’s stall policy, a commit may reflect inputs from only some spanned members. The commit carries evidence pointers; checking the pointers indicates which members’ inputs were present. Do not assume every spanned member contributed to every commit.

A stalled composite organism does not block upstream pipelines

If the organism’s committee loses majority or lags, the spanned members’ pipelines are unaffected. Fall back to binding per-member handles directly; the organism’s precomputation is a convenience, not a dependency.

What to do when your agent relies on an organism that changes

Organism Config fingerprints change for three reasons:

  • Organism upgrade. The organism’s content, ACL, or spanned member set changed; its fingerprint bumps independently.
  • Upstream member retirement. A member the organism spans published a new stable id; the organism inherits the change if it pinned the old stable id.
  • Upstream member content bump (only if pinned). If the organism pinned the upstream content hash, an TDX Measurements or ACL bump in the upstream bumps the organism’s fingerprint.

In every case the old handle starts failing with ConnectTimeout — or, better, the organism emits a RetirementMarker on its stream pointing at the replacement. The operator’s change channel should warn ahead; the integrator’s process should include a path to recompile against the new CoalitionConfig (or OrganismConfig) and restart.

Cross-references

Cross-member flows

audience: integrators

This page catalogues cross-member flows an agent may run and indicates which are cheap at the integrator level versus when a composite organism is warranted.

The underlying theory for block-building cross-chain cases is in the builder book’s cross-chain chapter. The coalition layer formalises its Shape 3 (bridge organism) as a composite organism and generalises the pattern beyond block-building to any mix of lattices and standalone organisms. This page is the integrator-facing view.

Four recurring flows

Paired bundles (two block-building lattices)

An agent publishes bundle A to offer[L1] and bundle B to offer[L2], expecting paired-slot commits.

  • Without a composite organism. Keep a per-agent correlator table keyed by bundle id; watch both lattices’ AuctionOutcome and join. Handle partial fills (A committed, B did not) with post-bond collateral or on- chain HTLC logic. This is the builder book’s Shape 1.
  • With an intents organism. Publish one intent to the organism’s write stream; the organism routes sub-bundles to each target lattice’s offer. Subscribe to the organism’s RoutedIntents for cross-chain outcome reconciliation.
  • Decision rule. If only one searcher runs the correlator, keep it in the agent. If three unrelated agents would each run the same correlator, an intents organism is warranted.

Cross-origin attribution (lattice + lattice)

A bundle submitted on lattice A but captured MEV on lattice B. Without coordination, tally[A] never sees the attribution on B’s block; tally[B] sees it but without knowing the origin was A.

  • Without a composite organism. Subscribe to both tally[A] and tally[B], join in memory on submission ids, compute the cross-origin view locally.
  • With a shared-ledger organism. One Shared::<Refund>::read handle yields aggregated attribution across all members the ledger spans.
  • Decision rule. If on-chain settlement requires a pre-aggregated attestation (e.g. one signature for a cross-chain refund claim), the organism is load- bearing. If each consumer can perform the join, the organism is a convenience.

Oracle + lattice correlation (organism + lattice)

An agent that needs to correlate an oracle organism’s price feed with block-building auction outcomes on one or more lattices. The members are heterogeneous: one is a standalone organism, the others are lattices.

  • Without a composite organism. Subscribe to the oracle organism’s feed and each lattice’s AuctionOutcome; join in memory with a timestamp tolerance window.
  • With a correlator organism. The organism’s commit pairs (oracle_tick, lattice_slot) tuples under one attested key, letting multiple downstream agents consume the same correlation without re-computing. When a coalition ships an Almanac the organism has opted into, both the oracle tick and the lattice slot align to almanac ticks, providing a shared correlation window.
  • Decision rule. Do three different agents need the same correlation? If yes, the organism amortises.

Cross-member observability

A dashboard, an analytics agent, or an oncall who wants “one view of the coalition’s activity” — across lattices, standalone organisms, or both.

  • Without a composite organism. N member subscriptions plus local aggregation.
  • With the coalition’s Atlas module. Start from the Atlas (directory of members, with endpoint hints); subscribe per member. Atlas is the reference; the aggregation remains the integrator’s.
  • Decision rule. Atlas pays off once more than one dashboard operator exists. A single on-call team can skip it; most coalitions ship an Atlas anyway because the cost is small and the coordination benefit is high.

The decision framework

Every cross-member flow reduces to one question:

Do three different agents (searchers, dashboards, analytics) need the same pre-aggregated fact?

If yes, a composite organism is the right shape: commit once per slot, consume N times.

If no, a per-agent driver is the right shape: keep the logic where the decisions are made.

A composite organism is not generic cross-member infrastructure. It is a mosaik organism with a narrow public surface and the same operational cost as any other committee-backed organism. Use it when a committed, reusable fact pays for the cost; use an in-agent driver when it does not.

What the coalition layer does not give you

  • Atomic cross-member commits. The coalition does not provide send-both-or-neither. See atomicity.
  • Cross-coalition coordination. Two CoalitionConfigs on the same universe are two handshake tokens; they do not coordinate. A cross- coalition commit resolves to a composite organism folding the relevant members directly, referenced independently by both coalitions.
  • Trust in a composite organism beyond its committee. A composite organism’s commit is trustworthy up to its committee’s assumption plus the upstream members it reads. Know the trust shape before relying on it.

Cross-references

Coalition overview

audience: operators

A coalition is an operator-published handshake token naming a set of mosaik members — block-building lattices, standalone organisms, and zero or more composite organisms (cross-member organisms) — and handing the set to integrators as one CoalitionConfig they compile in. A coalition may also ship up to four modules (Atlas, Almanac, Chronicle, Compute, Randomness) and an optional coalition-scoped ticket issuer under the same handshake.

This page is the operator’s introduction: what running a coalition means, what the operator owns, and what they do not.

Operator roles, often one team

Running a coalition means any combination of the following roles, often held by the same team:

  • Lattice operator — responsible for one LatticeConfig: its committees, its ACL, its organism rotations. Lattice operations are covered by the builder operator book. The coalition layer does not change any lattice-operator responsibilities.
  • Standalone-organism operator — responsible for one organism living directly on the universe (an oracle feed, an attestation aggregator, an identity substrate, …). Same shape as any mosaik-native service: a committee, a Config, a narrow public surface.
  • Composite-organism operator — responsible for one composite organism’s committee: running the binaries, holding the admission secrets, rotating the attestation images if TDX-gated. Organisms are coalition- independent; the same organism may be referenced by several coalitions.
  • Module operator — responsible for an Atlas, Almanac, Chronicle, or Compute committee. Mechanically identical to running any other coalition- scoped organism; the shape is specified in basic services.
  • Ticket-issuer operator — responsible for the coalition-scoped ticket issuance root when the coalition ships one. See ticket issuance.
  • Coalition operator — responsible for publishing and maintaining the CoalitionConfig: keeping its content accurate, notifying integrators when referenced members’ stable ids bump, and retiring the coalition instance name cleanly when it is no longer needed.

A single team commonly holds two or more of these roles.

What the coalition operator owns

  • The CoalitionConfig struct and its serialised fingerprint.
  • A published change channel (release notes, a CHANGELOG, an RSS feed — whatever), through which you notify integrators of member stable-id bumps, referenced-organism upgrades, or composition changes.
  • The set of OrganismConfigs referenced by the coalition (if you also run the modules and any organisms).
  • The set of OrganismRefs the coalition composes (role name, stable id, optional content hash for each referenced standalone organism).
  • The optional coalition ticket issuer.
  • A coalition-scoped operator handshake page — one URL or repository section integrators can link in their own docs.

What the coalition operator does not own

  • The referenced members. The coalition operator references lattices and standalone organisms; they do not admit peers into them, issue tickets on their behalf, or dictate internal parameters.
  • The referenced organisms. Each organism’s identity is independent of any coalition. The coalition operator references the organism; the organism operator controls its committee and Config.
  • Member stable ids. When a referenced member retires, the coalition operator updates the CoalitionConfig to match; they do not dictate the per-member operator’s retirement cadence.
  • Cross-operator contracts. Multi-operator coalitions bring SLAs, data-sharing arrangements, and attribution splits — all negotiated out of band. The blueprint does not provide a standard form.
  • Integrator lifecycle. Integrators compile in and recompile on their own schedule. A compiled-in CoalitionConfig cannot be revoked; the coalition operator publishes a new one and relies on integrators to upgrade.
  • Member behaviour. A member’s misbehaviour is addressed by publishing an updated CoalitionConfig that drops or replaces it. The coalition operator has no protocol-level power to constrain a member.

What per-member operators can expect from a coalition operator

Worth formalising with any member referenced:

  • Notification of inclusion. The coalition operator informs the per-member operator of the reference at publication time. The blueprint does not enforce this; it is a courtesy.
  • No admission requests. The coalition operator does not ask the per-member operator to issue special-case tickets for composite organisms or modules. Committee members bond into referenced members as ordinary integrators under the member’s normal admission policy.
  • Observability of referenced members’ public surfaces only. The coalition operator does not expect private plumbing access.
  • Bump coordination. Member stable-id bumps (retirements) are notified to the coalition operator via the per-member operator’s integrator channel ahead of cutover; this lets the coalition operator publish a matching CoalitionConfig without a ConnectTimeout gap. Routine content-hash bumps (TDX Measurements rotations, ACL rotations) do not require coalition-level updates unless composite organisms opted to pin the content hash.

A typical coalition’s shape

Three common archetypes:

  • Umbrella coalition. One operator; several lattices across related chains (every chain in a superchain stack, every chain in an L2 family). Modules: usually Atlas at minimum, often Chronicle. Composite organisms: often an intent router or shared ledger.
  • Service coalition. One operator; one or a handful of standalone organisms composed together (an attestation aggregator paired with an identity substrate; an oracle feed paired with an analytics pipeline). Often no lattices at all. Almanac is common because organisms without slot clocks benefit from a shared tick.
  • Multi-operator coalition. Multiple operators, each running one or a few members (lattices, standalone organisms, or both); one operator runs the coalition and one or more composite organisms. Common when an operator grouping wants a shared attribution or routing layer while the underlying members operate independently. An optional coalition-scoped ticket issuer is more likely here.

All three archetypes use the same CoalitionConfig shape; the difference is who runs what.

Critical path

  • Keep the CoalitionConfig in sync. When a referenced member retires or a referenced organism bumps, publish a new coalition fingerprint promptly.
  • Operate modules, the optional ticket issuer, and any organisms commissioned. Standard committee-organism operations: monitor, rotate, respond to anomalies.
  • Respond to integrators. Three typical questions: the current coalition composition, the cause of a ConnectTimeout, and how to bind to a newly shipped organism or module. The handshake page answers the first; the change channel the second; per-service docs the third.

Off the critical path

  • Per-member operations for members not run by the coalition operator. Those members operate themselves.
  • Inter-member consensus. None exists; the coalition is not a consensus unit.
  • Cross-coalition coordination. Two coalitions coexist on the universe and do not coordinate.

Cross-references

Quickstart — stand up a coalition

audience: operators

This runbook brings up a minimal coalition: one CoalitionConfig referencing two existing members (two block-building lattices, two standalone organisms, or one of each) and shipping one module — an Atlas — that publishes a per-coalition directory. Assumptions:

  • The members to be referenced exist. If any are block- building lattices not yet run by the operator, follow the builder operator quickstart first; if any are standalone organisms not yet run, follow the organism crate’s runbook.
  • Familiarity with the builder operator workflow: systemd units, published handshake pages, committee bring-up, TDX Measurements publication. The discipline is identical for any organism committee.
  • The coalition meta-crate (coalition) exists in a form sufficient to derive CoalitionConfig fingerprints. Until v0.2 lands, this is a paper exercise; the steps below are the target shape.

Estimated time to first CoalitionConfig: two engineer- days, assuming referenced members and the Atlas crate are already running.

Step 1 — enumerate the members to reference

Record, for each member, the canonical stable id (and optional content hash, if you choose to pin it) as published by its operator.

member                        kind      stable_id (hex)      content_hash       ticket-issuance root
-----------------------------+---------+---------------------+------------------+----------------------
ethereum.mainnet               lattice   0x…                  (unpinned)         0x…
unichain.mainnet               lattice   0x…                  (unpinned)         0x…
price-feed.eur                 organism  0x…                  0x…                0x…

Do not invent stable ids locally. Always use the per- member operator’s authoritative value. A per-member operator’s stable id that cannot be reproduced from its published Config definition is a member-level issue; do not paper over it in the coalition.

Step 2 — pick the coalition name

Short, stable, namespaced. Examples:

  • ethereum.superchain
  • mev.mainnet-q2
  • oplabs.testnet
  • signals.euro-fx

The name is folded into the coalition fingerprint; a typo propagates through every module derivation. Pick once. Rename via a new instance name, never via in-place edit.

Step 3 — decide which modules to ship

One module suffices for a minimal coalition. Atlas is the usual first choice:

  • Small state machine — one MemberCard commit per referenced member.
  • Low trust requirement — usually non-TDX, majority- honest.
  • High utility — integrators pin the Atlas in their own docs as the canonical coalition-composition reference.

Ship Almanac and Chronicle on their own schedules. Specifications in basic services.

A concrete cross-member problem (paired-bundle auctions, cross-chain attribution, oracle/lattice correlation) motivates commissioning a relevant organism beyond the modules. Each organism is a separate crate and committee; organisms are coalition-independent, so the same organism may also be referenced by other coalitions.

Step 4 — draft the CoalitionConfig

use builder::LatticeConfig;
use coalition::{CoalitionConfig, ModuleConfig, OrganismRef};

pub const ETHEREUM_MAINNET: LatticeConfig<'static> = /* from ethereum.mainnet operator */;
pub const UNICHAIN_MAINNET: LatticeConfig<'static> = /* from unichain.mainnet operator */;
pub const EUR_PRICE_FEED:   OrganismRef<'static>   = OrganismRef {
    role: "oracle",
    stable_id: /* from the price-feed operator */,
    content_hash: None,
};

pub const SUPERCHAIN_ATLAS: ModuleConfig<'static> = ModuleConfig {
    name: "atlas",
    content: /* atlas content params */,
    acl:     /* TicketValidator composition */,
};

pub const SUPERCHAIN_ATLAS_ORG: OrganismRef<'static> =
    OrganismRef {
        role:         "atlas",
        stable_id:    /* derived from SUPERCHAIN_ATLAS */,
        content_hash: None,
    };

pub const ETH_SUPERCHAIN: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "ethereum.superchain",
        lattices:  &[
            ETHEREUM_MAINNET.stable_id(),
            UNICHAIN_MAINNET.stable_id(),
        ],
        organisms: &[EUR_PRICE_FEED],
        atlas:             Some(SUPERCHAIN_ATLAS_ORG),
        almanac:           None,
        chronicle:         None,
        compute:           None,
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: RetirementPolicy::default(),
    };

Note: an OrganismConfig does not fold a coalition root; organism identity is independent. For a module like Atlas, the meta-crate’s derivation routes the identity under COALITION_ROOT.derive("module").derive("atlas") internally when the helper atlas() returns the matching OrganismRef.

Step 5 — freeze the fingerprint

The derivation order is:

  1. Compute COALITION = blake3("coalition|" || SCHEMA_VERSION_U8 || "|" || name).
  2. Compute COA_LATTICES = ordered stable ids.
  3. Compute COA_ORGANISMS = ordered stable ids (plus content hashes if pinned per-organism). Standalone and composite organisms share this slice.
  4. Compute COA_MODULES = ordered ModuleConfig fingerprints.
  5. Compute COA_TICKETS = TicketIssuerConfig fingerprint if present, else 0 bytes.
  6. Compute COALITION_ROOT = blake3(COALITION || COA_LATTICES || COA_ORGANISMS || COA_MODULES || COA_TICKETS).
  7. Module identities are derived from COALITION_ROOT via COALITION_ROOT.derive("module").derive(name).

Once the fingerprint is frozen, record its hex in release-notes.md. Integrators verify that hex against the struct they compile.

Step 6 — stand up the Atlas (and any other modules)

Every module is a mosaik-native organism (specifically, coalition-scoped). To bring up the Atlas committee:

  1. Install the Atlas binary on committee hosts (default N = 3; scale up as needed).
  2. Bootstrap Raft peers on the shared universe using the Atlas’s GroupId derived from its OrganismConfig under COALITION_ROOT.derive("module").derive("atlas").
  3. Publish the Atlas’s TDX Measurements (if TDX-gated) or the committee roster (if not).

Bring-up details are in the Atlas crate’s runbook and in Running an organism. Atlas does not require TDX.

Step 7 — publish the handshake

Collect everything integrators need:

  • CoalitionConfig Rust const (or the hex fingerprint paired with the struct definition).
  • The ordered list of referenced LatticeConfigs with links to each lattice operator’s handshake.
  • The ordered list of referenced OrganismRefs with role names, stable ids (plus content hashes if pinned), and a link to each organism operator’s handshake. Standalone and composite organisms share this shape; composite-organism entries additionally note TDX Measurements and state-machine signature where applicable.
  • Each module’s ModuleConfig with TDX Measurements, state-machine signature, and a short description.
  • A statement of which modules the coalition ships and which it does not — silence is ambiguous.
  • The coalition-scoped ticket issuer root, if any.
  • An initial peer hint for the shared universe.
  • Your change channel (email, feed, repo).

Post as a single page on the operator site or handshake repo. Link integrators to it.

Step 8 — notify integrators

A message on the change channel announcing the coalition’s first CoalitionConfig fingerprint is sufficient. Waiting integrators compile in the constant and open handles.

Ongoing operations

Day-to-day work is covered by the other operator pages:

Failure modes

  • Integrators report ConnectTimeout. Either the published CoalitionConfig drifted from the live deployment, or a referenced member retired and the coalition operator has not republished. Recompile the struct, freeze the fingerprint, publish.
  • A module’s committee lost majority. Standard mosaik recovery. Referenced members and referenced organisms continue; integrators reading the module temporarily see no new commits.
  • A referenced member retired silently. The per- member operator should have notified the coalition operator. File an anomaly with them, publish a new CoalitionConfig against the new stable id, and tighten change-channel discipline with that operator.

Cross-references

Running an organism

audience: operators

Operating an organism is, at the protocol level, identical to operating any mosaik-native committee organism: a committee, a state machine, a narrow public surface. This page is the delta that applies when the organism is composite — when it spans multiple members (lattices, standalone organisms, or a mix) — so the operator must track per-member health rather than one upstream.

Modules (Atlas, Almanac, Chronicle, Compute, Randomness) are coalition-scoped organisms; the same rules apply. Each module’s crate publishes its own page once commissioned.

For the base runbook — systemd units, dashboards, incident response — follow the builder operator runbooks. Each per-organism crate publishes its own page once commissioned.

What to add on top of a single-committee runbook

  • Per-member subscription health. A composite organism reads from multiple members’ public surfaces. The dashboard carries one subscription-lag metric per spanned member, not an aggregated metric. A composite organism that stalls typically stalls on one member first.

  • Per-member ticket health. Committee members hold tickets from each spanned member’s operator. When a per-member operator rotates their ticket-issuance root, the organism’s bonds into that member break until new tickets are issued to the committee. Monitor ticket validity horizons per member.

  • Member-identity monitoring. When a referenced member retires (stable id changes) or bumps its content hash (if the organism pinned content), the organism’s own Config fingerprint is stale; the organism must be redeployed under an updated OrganismConfig. Detect this before integrators do.

  • Cross-operator communications. A composite organism with members run by different operators requires a standing channel with each — at minimum a mailing list or chat channel for advance announcements of retirements and rotations.

The lifecycle of a composite organism commit

  1. Committee driver watches each spanned member’s public collection / stream.
  2. An upstream event fires; the driver wraps it in an Observe* command with an evidence pointer back to the upstream commit.
  3. The organism’s Group commits the Observe* via Raft.
  4. Periodically (or on an apply-deadline timer), the driver issues an Apply command. The state machine reads accumulated observations and commits the organism’s own fact.
  5. The organism’s public surface serves the committed fact to integrators and to any downstream consumers (other organisms, including composite ones that fold this one in).

Every step is standard mosaik machinery. The organism- specific work is the driver’s multi-subscription logic.

Rotations

A composite organism rotates like any other organism:

  • Committee member rotation. Add a new member under the same OrganismConfig; drain the old member; decommission. No fingerprint change.
  • Committee admission policy rotation (e.g. a TDX Measurements bump). Requires a new OrganismConfig fingerprint. Announce to any coalition operators referencing the organism and follow the rotations and upgrades sequence.
  • Spanned-member-set rotation. Adding or removing a spanned member changes the organism’s content fingerprint. This is a larger change; typically accompanied by a fresh OrganismConfig publication and a notice to referencing coalitions.

Rotations that do NOT break integrators

  • Committee member swaps under a stable OrganismConfig. Integrators see a brief latency bump during drain; no handle failures.

Rotations that DO break integrators

  • Any OrganismConfig fingerprint bump. Integrators compiled against the old config see ConnectTimeout on the organism handle until they recompile against the new OrganismConfig (and any coalition referencing it updates its CoalitionConfig). Announce ahead of time via the change channel.

Retirement

When a composite organism’s committee is shutting down permanently, the committee emits a RetirementMarker as its final commit on each public primitive. The marker carries:

  • effective_at — the Almanac tick or wall-clock at which the committee ceases to commit;
  • replacement — an optional pointer to the replacement organism so integrators rebind cleanly rather than timing out.

If any referencing coalition ships a Chronicle, the retirement lands as ChronicleKind::OrganismRetired in the next Chronicle entry.

Incident response specific to organisms

Two incident classes to add to your playbook on top of the single-organism classes in builder incident response.

Evidence-pointer resolution fails on replay

Symptom: a committee member replaying the log fails to resolve an evidence pointer to an upstream member commit. Cause: the upstream member committed the fact, the organism observed it, but the member has since gone through a state compaction / reorg that removed the referenced commit from the public surface the organism reads.

Response:

  • The organism state machine is required to reject such replays, not tolerate them.
  • Confirm the issue is upstream-member retention, not organism state.
  • Coordinate with the per-member operator. The fix is usually member-side configuration: longer retention on the public surface the organism subscribes to.

One spanned member goes dark

Symptom: no events from one of the spanned members’ public surfaces for multiple slots (or multiple publish ticks, if the member is an organism without a slot clock).

Response:

  • Confirm with the per-member operator whether the outage is on their side or on the subscription.
  • If on their side, fall back to the stall policy. A organism committing partial evidence yields degraded commits; one stalling per slot yields no commits until the member returns. Integrators were warned in the composition-hooks doc.
  • If on the subscription side: mosaik transport troubleshooting; nothing organism-specific.

Cross-references

Multi-operator coalitions

audience: operators

A multi-operator coalition is one whose referenced lattices, standalone organisms, or composite organisms are operated by different teams. The blueprint does not make multi-operator composition special: a CoalitionConfig references member stable ids regardless of who runs them. Coordination patterns succeed or fail based on a few out-of-band agreements, catalogued below.

A multi-operator coalition provides a shared handshake and a coordination channel; nothing more.

The blueprint minimum

The coalition operator needs the stable id of each referenced member. Any operator holding those ids can publish a CoalitionConfig including those members; there is no technical gate on referencing, and the CoalitionConfig does not require the per-member operator’s signature.

This is intentional. A stable-id reference is not a claim of authority over the member. A per-member operator objecting to a coalition reference has no technical recourse, and the reference also has no technical consequence: every organism committee member still needs tickets from each per-member operator to bond into those members’ public surfaces. The distinction — a coalition as a shared handshake without authority over its members — is the point Buterin draws on a different surface in DAOs are not corporations (2022): decentralisation is worth paying for where it buys censorship-resistance and unpredictability- resistance, not where it imitates corporate hierarchy. A coalition in this blueprint is a coordination layer in the first sense, not an instrument of control in the second.

What a multi-operator coalition agreement should cover

Documented even when trust between operators is high.

Notification cadence

  • Member retirements (stable-id bumps). The per- member operator notifies the coalition operator at least one business day ahead of a retirement.
  • Content-hash bumps that matter to organisms pinning content (TDX Measurements rotations on TDX-gated surfaces). Coordinate with any organism operator whose pinning policy is affected.
  • Ticket rotations. When a per-member operator rotates their ticket-issuance root, organism committee members need new tickets before cutover.
  • Retention changes. A member shortening retention of a public surface a composite organism subscribes to breaks organism replay. Notify the coalition operator and the organism operator.

Ticket issuance for organism committee members

The organism committee reads each spanned member’s public surfaces and so requires per-member tickets. Agreements should cover:

  • Who issues. Each per-member operator issues tickets for organism committee members, exactly as for any integrator.
  • Under what policy. Organisms usually need read- only tickets on specific surfaces (for a lattice: UnsealedPool, tally::Refunds; for an oracle organism: its feed stream). Scope accordingly.
  • Rotation schedule. Tickets expire. A rotation cadence matching the per-member operator’s standard schedule is acceptable; unannounced rotations are not.

Optional coalition-scoped ticket issuer

A multi-operator coalition may ship a coalition-scoped ticket issuer (see ticket issuance). Components — organisms, modules, even external integrators — decide per-component whether to recognise its tickets. No component is required to. A multi-operator coalition agreement can document which components plan to recognise the coalition issuer, but recognition itself is always in each component’s own TicketValidator composition.

Organism governance

When multiple members contribute inputs to one organism, the organism is itself a governance concern. Agreements cover:

  • Who runs the committee? Often the coalition operator; sometimes a subset of the per-member operators; occasionally a separate team. Organism identity is coalition-independent: the same committee serves every coalition that references it.
  • Who decides on Config bumps? The organism operator, informed by the affected per-member operators and by referencing coalitions.
  • Conflict resolution. The escalation path when the organism commits a record one per-member operator disputes (an attribution split, a cross-feed correlation).

None of this is in-protocol; all of it is contract. The coalition does not arbitrate.

Publishing a multi-operator coalition

The handshake page makes multi-operator coalition visible:

  • Per-member links. Each LatticeConfig or OrganismRef reference includes a link to the corresponding per-member operator’s handshake page. Composite-organism references additionally link to the organism operator’s handshake.
  • Operator roll call. A table listing each operator and the roles it holds (lattice, standalone organism, composite organism, module, ticket issuer, coalition).
  • Multi-operator coalition change channel. Typically a shared channel across all participating operators rather than the coalition operator’s individual channel, so that member-side changes are visible to every participant in-flight.

What multi-operator coalition does not change

  • Mosaik-level security. Each member’s ACL is unchanged. Each organism’s ACL is unchanged.
  • Atomicity. No cross-member atomic commit. Multi-operator coalition does not provide it; no contract can.
  • Integrator ergonomics. Integrators still compile one CoalitionConfig; a multi-operator coalition is indistinguishable from a single-operator coalition at the handle API.

A healthy multi-operator-coalition checklist

  • Each referenced per-member operator has been notified.
  • Each referenced organism operator has been notified.
  • Ticket issuance for organism committee members is documented per member.
  • The change channel covers member retirements, content-hash bumps, ticket rotations, and organism config changes.
  • The handshake page lists every operator and their role.
  • The coalition’s modules and any referenced organisms have a documented stall / degradation policy consistent with each spanned member’s expected availability.

Cross-references

Rotations and upgrades

audience: operators

Rotation discipline at the coalition layer is thin: most rotations occur inside one member (a lattice or a standalone organism) or inside a composite organism or module. The coalition operator’s task is to republish the CoalitionConfig when any referenced component changes identity in a way that folds into COALITION_ROOT. This page lists the rotations that materially affect a coalition and the operation order for each.

For rotations inside a block-building lattice organism, follow the builder rotations page. For rotations inside a standalone organism, follow that organism’s own runbook.

Rotations that change a coalition’s fingerprint

Any of the following forces a new CoalitionConfig fingerprint. Publication is not optional: integrators compiled against the old fingerprint see ConnectTimeout on every handle until they recompile against the new one.

  1. A referenced lattice’s stable id changes (retirement).
  2. A referenced organism’s stable id changes (retirement of a standalone or composite organism).
  3. A referenced composite organism’s OrganismConfig fingerprint changes and the coalition pinned the content hash (content, ACL, span, or TDX Measurements bump on a TDX-gated organism).
  4. A module’s ModuleConfig fingerprint changes (content, ACL, or TDX Measurements bump).
  5. The coalition’s lattice set changes (add or remove a lattice).
  6. The coalition’s organism set changes (add or remove a standalone or composite organism).
  7. The coalition’s module set changes (add or remove a module).
  8. The coalition’s ticket issuer is added, rotated, or removed.
  9. The coalition instance name changes (rare — effectively a retirement; see below).

Rotations that do not change a coalition’s fingerprint

  • Committee member rotations inside a referenced member, under a stable per-member Config.
  • Committee member rotations inside a composite organism or module, under a stable OrganismConfig / ModuleConfig.
  • TDX Measurements republications that match the previously pinned value (i.e. the image was rebuilt from the same source).
  • Per-member content-hash bumps (TDX Measurements rotations, ACL rotations) if organisms pin only the stable id, not the content hash. Organisms that pinned content hash do bump.

These are invisible to integrators at the coalition layer. Documented per-member or per-organism, not per- coalition.

Ordering a member retirement

When a referenced member’s stable id changes, follow this sequence.

  1. Receive the retirement notification from the per- member operator via the multi-operator coalition change channel. The notification includes the old and new stable ids and the cutover time.
  2. Prepare the new CoalitionConfig. Update the member’s reference in the CoalitionConfig definition. Re-derive the coalition fingerprint. Modules re-derive automatically because COALITION_ROOT has changed. Commissioned organisms referenced by the coalition re-derive only if they themselves span the retired member.
  3. Redeploy modules under the new OrganismConfigs. Because each module’s content folds the coalition root, module fingerprints have bumped. Bring up new committee members on the new OrganismConfigs while old members continue on the old ones; rotate over.
  4. Publish the new CoalitionConfig fingerprint on the handshake page and change channel.
  5. Wait for integrators to recompile. Old- fingerprint handles time out (or, better, see a RetirementMarker from each retiring committee pointing at the replacement); integrators reach out if they miss the change.
  6. Retire the old module deployments once the old CoalitionConfig is no longer in use by the integrators the operator cares about. Each committee emits a terminal RetirementMarker before shutdown.

Ordering a composite-organism or module upgrade

A composite organism or module’s Config may change for reasons other than upstream member retirements: new content parameters, TDX Measurements bump, ACL change.

  1. Stand up the new deployment under the new OrganismConfig / ModuleConfig alongside the old.
  2. Update any referencing coalitions’ CoalitionConfigs to reference the new fingerprint. Recompute each coalition fingerprint.
  3. Publish each new CoalitionConfig.
  4. Announce the change via the change channel, with migration notes. If any referencing coalition ships a Chronicle, its next commit records the rotation.
  5. Retire the old deployment. The committee emits a RetirementMarker pointing at the new deployment so integrators rebind cleanly.

A transition window where old and new coexist is required; a hard cutover leaves every integrator timing out simultaneously.

Retiring a coalition

A coalition may be retired (renamed). Reasons:

  • The composition has drifted far enough from the original intent that a clean break is preferable to incremental bumps.
  • The set of operators participating in the coalition has reorganised.
  • Branding or regulatory considerations.

Sequence:

  1. Announce retirement with substantial lead time. Integrators relying on the coalition need weeks to migrate. A shipped Chronicle records the retirement in its next commit.
  2. Stand up the replacement coalition (e.g. ethereum.superchain-v2026q2) with a fresh CoalitionConfig fingerprint and the desired composition.
  3. Run both coalitions in parallel until most integrator traffic has migrated.
  4. Retire the old coalition’s modules (committees emit RetirementMarkers pointing at the replacement coalition’s modules) once integrator traffic drops to zero or acceptable levels. Referenced organisms are independent of the retired coalition and continue if other coalitions or direct integrators still use them.
  5. Publish a retirement note. The old CoalitionConfig fingerprint is formally deprecated; integrators still on it see ConnectTimeout once the old modules are down.

Do not reuse an instance name for a different composition. A retired coalition’s name is spent; reissuing it under a new composition would produce silent mis-bindings across the integrator base.

Cross-references

Designing coalitions on mosaik

audience: contributors

This chapter extends the design intros of zipnet and builder from one organism → one lattice → one coalition: a named composition of coexisting mosaik members — block-building lattices, standalone organisms (oracles, attestation fabrics, identity substrates, analytics pipelines, …), cross- member organisms (composite organisms), and up to five basic services (Atlas, Almanac, Chronicle, Compute, Randomness) plus an optional coalition-scoped ticket issuer.

The reader is assumed familiar with the mosaik book, the zipnet book, the builder book, and the two design intros cited above. This chapter does not re-derive content + intent addressing, the narrow-public-surface discipline, the shared-universe model, or within-lattice derivation; it uses them.

Stance

A coalition is an opt-in composition. The substrate has no primitive for compulsion: every bond is opt-in at the TicketValidator layer, member identity is independent of coalition membership, and basic services never gate member operation. Every design choice in this chapter follows from this baseline.

The problem, at N members

Builder composes six organisms under one LatticeConfig for one EVM chain, solving “one end-to-end pipeline for one chain” cleanly. It does not solve:

  • Cross-member coordination at scale. An agent operating across ten block-building lattices holds ten LatticeConfigs; one additionally correlating across an oracle and an attestation organism holds twelve handshakes. Driver code pairs facts across members, reconciles partial observations, and recovers outcome correlators. The same correlator is re-implemented per agent. The builder book’s Shape 1 is correct for two or three lattices and an unbounded implementation burden at ten-plus heterogeneous members.

  • Shared attribution. MEV captured on a block of lattice A originating from a searcher bundle submitted on lattice B — or a trade attributed by an analytics organism also reported by an oracle organism — is invisible to each service without explicit wiring. Ad hoc repetition is the same burden, one level deeper, across more boundary kinds.

  • Consistent cross-member observability. Operators running five members want one dashboard; analytics integrators want one API. Both want a named composition with a fingerprint that moves in lockstep with what they subscribe to. The Atlas basic service addresses this.

  • Operator coordination. Teams coordinating a set of members — every chain in a superchain stack, every oracle feed in a region, every deployment’s bonded organisms — need a naming unit for that coordination that does not itself become a consensus unit.

  • Durable provenance. Decisions outlive any one CoalitionConfig. An operator grouping needs a tamper-evident record of its own publications, rotations, and retirements — the Chronicle basic service addresses this.

Promoting “a set of members” to an in-consensus group collapses every member’s trust boundary into one committee. Builder rejected that shape at the organism level; promoting it one rung higher inherits the same objection at higher cost.

The correct rung is a fingerprint above the members that names them for discovery, basic services, and module derivation — without consensus, state, or admission authority. That fingerprint is a coalition.

Two axes of choice

Same two axes zipnet picked and builder reaffirmed. Each rung of the ladder inherits the zipnet conclusion; the coalition rung does too.

  1. Network topology. Does a coalition live on its own NetworkId, or share a universe with every other mosaik service?
  2. Composition. How do members and organisms reference each other without creating cross-Group atomicity mosaik does not support — and, now, without creating cross-coalition atomicity either?

The blueprint chooses shared universe + membership-by- reference + no cross-Group, cross-member, or cross- coalition atomicity. The three choices are independent; each has a narrow rationale.

Shared universe (unchanged)

builder::UNIVERSE = unique_id!("mosaik.universe") — the same constant zipnet and builder use. Every coalition, lattice, standalone organism, composite organism, and module lives on it. Different coalitions coexist as overlays of Groups, Streams, and Collections distinguished by their content + intent addressed IDs. An integrator caring about three coalitions holds one Network handle and three CoalitionConfigs. Because coalitions reference members rather than re-deriving them, an integrator already bonded to some of the included members observes no duplicate identity.

The alternative — one NetworkId per coalition, mirrored all the way up — is rejected on the same grounds the zipnet book rejects Shape A: operators already pay for one mosaik endpoint, services compose, and one additional endpoint per coalition would turn the coalition into a routing device, which is not the rung’s function.

Membership-by-reference

A CoalitionConfig is a parent struct. Unlike a LatticeConfig (which nests six organism Configs and hashes them together), a CoalitionConfig references existing member fingerprints without re-deriving the members’ organism IDs. This is the key decision of the coalition rung:

  COALITION        = blake3("coalition|" || SCHEMA_VERSION_U8
                          || "|" || coalition_name)
  COA_LATTICES     = ordered stable ids of referenced lattices
  COA_ORGANISMS    = ordered stable ids of referenced organisms
                     (including any composite organisms)
  COA_TICKETS      = optional TicketIssuerConfig fingerprint (0 bytes if absent)
  COALITION_ROOT   = blake3(
                       COALITION
                       || COA_LATTICES
                       || COA_ORGANISMS
                       || COA_TICKETS
                     )

Here COA_LATTICES[i] is the stable id of lattice i — not a re-derivation. Likewise COA_ORGANISMS[j] is the stable id the standalone organism (or composite organism) j publishes in its own handshake. Composite organisms are referenced by their own fingerprint just like any other organism. Builder’s lattice identity is:

  LATTICE(i) = blake3("builder|" || instance_name || "|chain=" || chain_id)
  + every organism's Config fingerprint inside that lattice

A coalition neither modifies LATTICE(i) nor the organism roots under it, nor the Config of any standalone organism or composite organism it references. A member referenced by three coalitions is one member; its operators issue tickets once, its integrators compile it in once, and its GroupIds are stable across coalition memberships.

Rationale for by-reference over by-containment:

  • Members predate coalitions. The first production organism and first production lattice ship before the first coalition. An integrator already bonded to a specific member must not have to re-bond when an operator composes that member into a new coalition.

  • Members outlive coalitions. Coalition membership is a composition choice and changes; member identity is an operator-level commitment. Coalitions must not force churn.

  • Members belong to multiple coalitions. The shared- universe choice implies a member may be referenced from several coalitions simultaneously — one per operator grouping, one per analytics vendor, one per umbrella grouping. Re-derivation would force a cartesian product of IDs.

Member reference shape

A member is referenced by two values: its stable id — the (instance_name, network_id) blake3 hash — which changes only on retirement; and its content hash, which folds the member’s ACL, TDX Measurements, and policy parameters and bumps with every operational rotation.

CoalitionConfig references members by stable id. Composite organisms and modules choose per-component whether they also pin the content hash. A read-only correlator that does not bond into TDX-gated surfaces pins only the stable id and survives TDX Measurements rotations in its upstream members. A composite organism whose committee bonds into a TDX-gated surface pins the content hash and redeploys on rotation.

The split decouples TDX Measurements rotation churn from coalition- level identity. A coalition referencing ten members rotating TDX monthly sees its COALITION_ROOT change only on member retirement or coalition membership change, not on routine operational rotations.

Open for v0.3 decision. Whether content-hash- pinning is a per-component choice or a coalition-wide policy is unresolved. Leaving it per-component for v0.2; CoalitionConfig may gain a policy flag later.

Builder’s LatticeConfig derivation already distinguishes the two in practice; this rung surfaces the distinction in the coalition-layer spec. Both LatticeConfig and OrganismRef expose a stable_id() accessor separate from their full fingerprint accessor.

Composite organisms as a recurring pattern

Composite organisms are organisms in the zipnet sense: one Config fingerprint, a narrow public surface, a ticket-gated ACL. What distinguishes them is that their content folds two or more member fingerprints. A composite organism’s identity does not fold a coalition root:

  ORGANISM(cfg) = blake3(
                      "organism|"
                      || SCHEMA_VERSION_U8
                      || "|" || name
                      || ordered spanned lattice references
                      || ordered spanned organism references
                      || content_fingerprint
                      || acl_fingerprint
                    )

  ORGANISM_committee = ORGANISM(cfg).derive("committee")

A composite organism is therefore referenced by zero, one, or many coalitions exactly as a lattice or any other standalone organism is. Its committee, state machine, and log are shared across those references. A composite organism misconfigured against the wrong spanned members derives a disjoint GroupId and surfaces as ConnectTimeout — the ladder’s standard debuggable failure mode.

Modules (Atlas, Almanac, Chronicle) are the only coalition-scoped components. Their identity derives under COALITION_ROOT.derive("module").derive(name) where name is "atlas", "almanac", or "chronicle". An optional ticket issuer derives under COALITION_ROOT.derive("tickets").

No cross-Group, cross-member, or cross-coalition atomicity

Every rung below refuses cross-Group atomicity. The coalition rung refuses cross-member and cross-coalition atomicity by the same argument:

  • Cross-Group (one member, two organisms) — refused by builder and by every organism’s own design. Organisms subscribe to each other’s public surfaces; there is no atomic multi-organism commit.
  • Cross-member (one coalition, two members) — refused by this blueprint. Composite organisms read public surfaces of the members they span; their state machine commits its own facts. A composite organism never forces two members to commit atomically.
  • Cross-coalition (two coalitions) — refused by this blueprint. Coalitions do not coordinate in consensus. A use case for cross-coalition coordination resolves either to an integrator spanning coalitions or to a new composite organism whose content fingerprint folds the relevant members (which are already referenced by both coalitions anyway).

Fixed shapes, open catalogs

The blueprint’s central discipline; restated because every downstream choice flows from it.

Specified

  • The CoalitionConfig struct and derivation rules. Every coalition has this shape; every coalition’s identity is computed this way.
  • The OrganismConfig and OrganismRef structs. Every organism (including composite organisms) and every standalone-organism reference has these shapes.
  • The five basic-service shapes (Atlas, Almanac, Chronicle, Compute). Every instance of “Atlas” in any coalition has the same Config signature, public surface, and derivation. Same for the other three. Specification in basic services.
  • The optional ticket-issuer shape. Specification in ticket issuance.
  • Membership discipline — by-reference, multi- coalition-compatible, no re-derivation; stable-id and content-hash split.

Left open

  • Whether any given coalition ships any basic services. A coalition with zero services is valid.
  • Whether any given coalition ships a ticket issuer.
  • The catalog of commissioned composite organisms. Each arrives when a cross-member problem forces it.
  • The catalog of standalone-organism categories and lattice classes. New categories arrive with their own books. Block-building lattices are the first specified class; attestation fabrics, oracle grids, DA shards, and other categories follow their own proposals.
  • Inter-coalition coordination. Coalitions coexist on the shared universe; a concrete need for coordination earns its way in through a fresh proposal.
  • Governance of the coalition itself. Who approves CoalitionConfig bumps, how operator groupings form and dissolve, what contracts multi-operator coalitions sign — all out of band.

Deliberately deferred (deferred-primitives space)

A family of primitives the blueprint refuses:

  • Enforceable policies over members — a CoalitionConfig declaring constraints members must satisfy (TDX Measurements requirements, bond minimums, code-audit attestations).
  • Taxation — a protocol-level mechanism for the coalition to collect fees from members’ commits.
  • Judiciary — an organism whose commits have protocol-level precedence over individual members’, resolving disputes.
  • Mandatory membership — any primitive whose absence renders a member’s commits invalid in the coalition’s view.
  • Legislation — a state machine in the coalition that members must query and conform to before acting.

Each is a coherent design space, and adopting any one forces the blueprint to rewrite the trust composition and rebuild every passage that assumes opt-in participation. Any future deferred-primitives proposal lives on its own branch and earns the transition; the current blueprint neither anticipates nor precludes one.

Flag in-source and in-docs as “deferred-primitives space” when the topic arises so the current scope is unambiguous.

Coalition identity

A coalition is identified by a CoalitionConfig folding every root input into one deterministic fingerprint. Operators publish the CoalitionConfig as lattice operators publish a LatticeConfig and organism operators publish their own Config; integrators compile it in.

pub const SCHEMA_VERSION_U8:    u8       = 1;
pub const COALITION_ROOT_SEED:  UniqueId = /* fixed */;

#[non_exhaustive]
pub struct CoalitionConfig<'a> {
    /// Schema version byte. Folded as the first element of
    /// every top-level identity preimage.
    pub schema_version: u8,

    /// Coalition root domain-separation seed. Constant
    /// across the blueprint; carried explicitly so the
    /// fingerprint stays self-describing.
    pub coalition_seed: UniqueId,

    /// Short, stable, namespaced name chosen by the
    /// coalition operator (e.g. "ethereum.superchain",
    /// "signals.euro-fx", "searcher-α").
    pub instance_name: &'a str,

    /// Ordered set of lattice stable ids this coalition
    /// references. Held by stable id so the coalition does
    /// NOT re-derive any lattice's organism IDs; a lattice
    /// retains a single canonical identity across every
    /// coalition that references it.
    pub lattices: &'a [UniqueId],

    /// Ordered set of organism references this coalition
    /// composes — any mosaik organism with a Config
    /// fingerprint living directly on the universe,
    /// including composite organisms whose `Config` folds
    /// multiple member references. A composite organism's
    /// identity is derived independently of any coalition;
    /// the same composite organism may be referenced by
    /// many coalitions.
    pub organisms: &'a [OrganismRef<'a>],

    /// Basic services the coalition ships. Each field
    /// holds an `OrganismRef` when shipped, `None`
    /// otherwise. See [basic services](./basic-services.md).
    pub atlas:      Option<OrganismRef<'a>>,
    pub almanac:    Option<OrganismRef<'a>>,
    pub chronicle:  Option<OrganismRef<'a>>,
    pub compute:    Option<OrganismRef<'a>>,
    pub randomness: Option<OrganismRef<'a>>,

    /// Optional coalition-scoped ticket issuer.
    /// Non-authoritative: no component is required to
    /// accept tickets from this issuer. Organisms opt in
    /// via their own TicketValidator composition.
    pub ticket_issuer: Option<TicketIssuerConfig<'a>>,

    /// Per-coalition retirement policy. Default: explicit
    /// republication on every content change.
    pub retirement_policy: RetirementPolicy,
}

#[non_exhaustive]
pub struct OrganismRef<'a> {
    pub role: &'a str,
    /// blake3((instance_name, network_id)); changes only
    /// on retirement.
    pub stable_id: UniqueId,
    /// Optional content hash (ACL, TDX Measurements, policy).
    /// Components that pin this redeploy on operational
    /// rotations.
    pub content_hash: Option<UniqueId>,
}

impl CoalitionConfig<'_> {
    /// blake3("coalition|" || schema_version || "|"
    ///         || coalition_seed || "|"
    ///         || instance_name || ...)
    pub const fn stable_id(&self) -> UniqueId { /* ... */ }
}

CoalitionConfig is lifetime-parameterised so runtime construction is a first-class path. All existing const instances continue to compile under 'static inference.

An integrator binds to the coalition by passing the CoalitionConfig into whichever member or organism handles they need:

use std::sync::Arc;
use mosaik::Network;
use builder::{LatticeConfig, UNIVERSE};
use coalition::{
    CoalitionConfig,
    SCHEMA_VERSION_U8, COALITION_ROOT_SEED,
    RetirementPolicy,
};

const ETH_SUPERCHAIN: CoalitionConfig<'static> =
    CoalitionConfig {
        schema_version:    SCHEMA_VERSION_U8,
        coalition_seed:    COALITION_ROOT_SEED,
        instance_name:     "ethereum.superchain",
        lattices: &[
            ETH_MAINNET.stable_id(),
            UNICHAIN_MAINNET.stable_id(),
            BASE_MAINNET.stable_id(),
        ],
        organisms: &[
            EUR_PRICE_FEED,
            INTENTS_ROUTER,
            SHARED_LEDGER,
        ],
        atlas:             Some(SUPERCHAIN_ATLAS_ORG),
        almanac:           None,
        chronicle:         None,
        compute:           None,
        randomness:        None,
        ticket_issuer:     None,
        retirement_policy: RetirementPolicy::default(),
    };

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let network = Arc::new(Network::new(UNIVERSE).await?);

    let eth_bid  = offer::Offer::<Bundle>::bid(&network, &ETH_SUPERCHAIN.lattices[0].offer).await?;
    let eur_feed = oracle::Feed::<Price>::read(&network, ETH_SUPERCHAIN.organisms[0].config()).await?;
    let intents  = intents::Router::<Intent>::publish(&network, &ETH_SUPERCHAIN.organisms[1]).await?;
    let atlas    = atlas::Atlas::<MemberCard>::read(&network, ETH_SUPERCHAIN.atlas().unwrap()).await?;
    // ...
    Ok(())
}

Every organism (composite, module, or standalone) exposes typed free-function constructors in the shape zipnet ships and builder reproduces (Organism::<D>::verb(&network, &Config)). Raw mosaik IDs never cross a crate boundary.

The coalition crate’s convenience surface

The coalition crate re-exports a small convenience surface so that book-level examples, composite organisms, and integrator quickstarts can use the same vocabulary without each reaching into mosaik’s module layout directly. The surface is stable across the blueprint; downstream crates depend on it rather than on mosaik’s primitive modules where both are interchangeable.

SymbolProvenance / role
coalition::Stream<T>Alias for mosaik::streams::Producer<T> on the write side, mosaik::streams::Consumer<T> on the read side.
coalition::Collection<K, V>Alias for mosaik::collections::Map<K, V>.
coalition::Network (re-export)mosaik::Network verbatim.
coalition::Network::subscribe_of::<T>(id)Extension trait wrapping network.streams().consumer::<T>().with_stream_id(id).build() for ergonomic organism reads.
coalition::TicketValidator (re-export)mosaik::TicketValidator verbatim.
coalition::Tdx (re-export)mosaik::tee::Tdx; carries .require_mrtd(...) and .verify_peer(...).
coalition::acl::ReputationFloorTicket composer binding admission to a reputation card floor. Consumes (UniqueId, f32).
coalition::acl::MarketSettlementTicket composer binding admission to a market settlement pointer.
coalition::when!Declarative macro for reactive conditions over Streams; compiles to .when() method chains on mosaik::streams.
coalition::unique_id! / const_blake3!Compile-time blake3 of byte literals; convenience wrapper around mosaik::primitives::unique_id!.
coalition::zipnet::SealClientThin wrapper over zipnet::Zipnet::<D>::submit(&network, &Config) that carries the committed digest back to the caller.
coalition::RetirementPolicyPer-coalition retirement policy; default is explicit republication on every content change.

The convenience surface is the book’s one central declaration of these symbols. Every chapter that uses Stream, Collection, ReputationFloor, when!, or SealClient imports them from coalition::*, not from mosaik/zipnet directly. Downstream crates that want the raw primitives are free to bypass the convenience surface, but the book’s prose does not.

Fingerprint convention, not a registry

Same discipline as zipnet and builder:

  • The coalition operator publishes the CoalitionConfig struct (or a serialised fingerprint) as the handshake.
  • Consumers compile it in.
  • If TDX-gated, the operator publishes the committee TDX Measurements for every organism (composite, module, or standalone) whose admission is TDX-attested. Per-member TDX Measurements are published by the per-member operator; the coalition operator re-publishes them for convenience, not as authority.
  • There is no on-network coalition registry. A directory collection of known coalitions may exist as a devops convenience; it is never part of the binding path.

Typos in the coalition instance name, in member fingerprint ordering, or in any organism’s parameters surface as Error::ConnectTimeout, not “coalition not found”. The library cannot distinguish “nobody runs this” from “operator is not up yet” without a registry, and adding one would misrepresent the error.

What a coalition is not

  • A member’s owner. A coalition references a member; per-member operators control admission, rotate keys, retire instances. The coalition’s CoalitionConfig updates independently.

  • A consensus unit. There is no coalition-level Raft group, no coalition state machine, no coalition log. The coalition layer adds naming, modules, and module derivation — no consensus.

  • A routing device. Coalitions do not carry traffic between members. Every member and organism discovers peers via mosaik’s usual gossip on the shared universe. The coalition fingerprint is a compile-time token, not a runtime hub.

  • An ACL root. A coalition does not issue tickets on behalf of referenced members. Each member’s TicketValidator composition is unchanged; each organism has its own TicketValidator. The optional ticket issuer is opt-in per component: components that want to recognise its tickets include its issuance root in their validator composition; others ignore it.

  • A closed catalog. Unlike builder’s six organisms, this blueprint does not enumerate a canonical set of lattice classes, organism categories, or composite organisms. Real members and composite organisms ship when a concrete problem forces them.

Four conventions (three inherited, one added)

Every organism the blueprint references — whether standalone, composite, or a module — reproduces the three zipnet conventions verbatim; the coalition adds one.

  1. Identifier derivation from the organism’s Config fingerprint. Inherited from zipnet.

  2. Typed free-function constructors. Organism::<D>::verb(&network, &Config) returning typed handles; raw IDs never leak across crate boundaries. Inherited from zipnet; mirrored by every organism in every lattice, every composite organism, and every module.

  3. Fingerprint, not registry. Inherited from zipnet; reaffirmed by builder and here.

  4. Membership-by-reference, module-by-derivation. New for the coalition rung. A CoalitionConfig folds member fingerprints as content without re-deriving their organism IDs; composite organisms are likewise referenced, not derived. Modules (Atlas, Almanac, Chronicle) and an optional ticket issuer are the components whose identity folds COALITION_ROOT.

What the pattern buys

  • Collapsed integrator model: one Network, one CoalitionConfig per coalition, typed handles on each referenced member, composite organism, and consumed module.

  • Operator pacing. A coalition starts as one operator’s set of members, adds a second operator’s member without touching the first’s, and adds a composite organism or module without forcing either per-member operator to change anything.

  • Clean retirement. A commissioned composite organism retires by the coalition’s next CoalitionConfig omitting it — or, if the organism itself is going away, by a retirement marker on its own stream. Integrators see ConnectTimeout, the ladder’s standard failure mode, or a clean upgrade pointer.

  • Cross-member services as organisms, not protocols. A shared-ledger composite organism, cross-feed correlator, cross-chain intent router, Atlas, or Almanac is a mosaik organism following the zipnet pattern. Its author reuses every primitive, ticket validator, and replication guarantee.

  • Open catalog. New lattice classes, organism categories, and composite organisms arrive on their own schedules and fold into the existing handshake shape without forcing the coalition layer to change.

Where the pattern strains

Three limitations a contributor extending this must be explicit about.

Member upgrades churn coalition-scoped identity

A member-level change bumping its stable id — a retirement — changes the corresponding entry in COA_LATTICES or COA_ORGANISMS for every coalition that references the member, which in turn changes COALITION_ROOT and every module derived under it.

The stable-id / content-hash split keeps routine operational rotations out of COALITION_ROOT: TDX Measurements rotations do not change the stable id and therefore do not cascade. A retirement does; retirement is rare and announced.

Commissioned composite organisms do not derive under COALITION_ROOT, so retirements ripple through modules only. A composite organism re-derives only when the members it itself spans retire or when its own content changes.

Wide composite organisms are heavy

A composite organism reading public surfaces from ten members simultaneously runs ten subscriptions, holds peer entries for ten ticket-issuance roots, and is sensitive to the liveness of all ten. The coalition blueprint does not make this easier; it makes it legible.

Commissioning contributors should consider sharding: a per-pair composite organism over interesting member pairs, composed by an integrator, is often cheaper and more debuggable than one wide composite organism.

The coalition is not cryptographically authoritative

A CoalitionConfig fingerprint is a naming convenience. It does not sign, commit on-chain, or expose a channel for per-member operators to discover which coalitions reference their member. A per-member operator objecting to being referenced has no technical recourse — anyone with a list of member stable ids can publish a CoalitionConfig.

This is intentional. The only cryptographic check is whether each referenced member admits the composite organisms’ committee peers via its own TicketValidator. Per-member and coalition operators negotiate references out of band.

Checklist for commissioning a new composite organism

  1. Identify the one or two public primitives. If the surface is not a small, named, finite set of streams or collections, the interface is not yet designed.

  2. Identify the members it spans. Record as ordered sequences of member references in the composite organism’s Config — lattices, organisms, or both. Order matters; changing it changes the fingerprint.

  3. Pick the composite organism’s name. Folded into the organism’s own derivation; no coalition root is involved.

  4. Define the Config fingerprint inputs. Content parameters affecting the state-machine signature, upstream public surfaces subscribed to, ACL composition.

  5. Write typed constructors. Organism::<D>::verb(&network, &Config). Never export raw StreamId/StoreId/GroupId across the crate boundary.

  6. Specify TicketValidator composition on the public primitives. ACL lives there. If the composite organism wants to recognise any coalition’s ticket issuer, its validator composition includes that issuance root directly; the composite organism chooses, the coalition does not impose.

  7. Decide per-member-failure behaviour. If member A is down, does the composite organism keep processing remaining members’ inputs or stall? Document as part of the composition contract.

  8. Document which members’ public surfaces are read. This is the composition contract; changes to it touch Composition.

  9. Declare dependency on any modules. If the composite organism aligns to Almanac ticks or observes Chronicle entries, state so in the crate documentation.

  10. Answer: does this composite organism meaningfully aggregate across members, or is it an integrator in disguise? If an ordinary integrator holding the same N member handshakes could do the same work, skip the composite organism. The pattern earns its keep when the aggregated fact is itself a commit with its own consumers.

  11. State the versioning story. If the answer to “what happens when one of the referenced members bumps its fingerprint?” is not defined, the design is incomplete.

Cross-references

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 member 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
                         (including any composite organisms)
                      || 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>

  // Composite-organism IDs: derived independently of any coalition.
  ORGANISM_c    = blake3("organism|" || SCHEMA_VERSION_U8
                            || "|" || name
                            || spanned members
                            || content
                            || acl)

  // Module IDs: the 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")

Member identity travels with the member; a composite organism’s identity travels with the organism. Only module identity (and the optional ticket issuer) is coalition-bound. See topology-intro — Membership-by-reference and topology-intro — Composite organisms as a recurring pattern.

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, &ETH_SUPERCHAIN.lattices[0].offer ).await?;
let uni_bid   = offer::Offer::<Bundle>::bid (&network, &ETH_SUPERCHAIN.lattices[1].offer ).await?;
let eth_tally = tally::Tally::<Attribution>::read(&network, &ETH_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::<MemberCard>::read(&network, ETH_SUPERCHAIN.atlas().unwrap()).await?;
let almanac   = almanac::Almanac::<AlmanacTick>::read(&network, ETH_SUPERCHAIN.almanac().unwrap()).await?;

// Composite-organism handles — the same shape as any other organism.
let intents   = intents::Router::<Intent>::publish(&network, ETH_SUPERCHAIN.organisms_by_name("intents").unwrap()).await?;
let ledger    = ledger ::Shared ::<Refund>::read  (&network, ETH_SUPERCHAIN.organisms_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 composite organism handle; an observability operator holds atlas::read and opens per-member handles from there.

Public surface summary

The coalition’s outward-facing primitives decompose into:

  1. 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.

  2. Every public primitive of every referenced standalone organism, unchanged. Each organism’s own book is the reference.

  3. Every module’s public surface (Atlas, Almanac, Chronicle — whichever are shipped), specified in basic services.

  4. One or two public primitives per referenced composite organism, following the same narrow-surface discipline as every other organism.

For an example coalition containing two composite organisms — an intent router and a shared ledger — plus Atlas and Almanac as modules, the coalition’s own added surfaces might look like:

ComponentWrite-side primitivesRead-side primitives
atlas(committee-only)Atlas map (MemberIdMemberCard)
almanac(committee-only)Ticks stream
intentsPublish<Intent> streamRoutedIntents collection (per slot, per target lattice)
ledger(internal commits only)SharedRefunds collection (keyed by origin member)

“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 composite organism names are per-commission choices.

An example coalition: ethereum.superchain

Concrete walk-through of one plausible coalition. None of the composite organisms 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 by OrganismRef.
  • Modules shipped: Atlas (directory), Almanac (tick beacon). Chronicle not shipped in this example; the operator can add it later without reshuffling members.
  • Composite organisms referenced:
    • intents — a cross-chain intent router (reads from each lattice’s unseal::UnsealedPool, commits per- slot RoutedIntents keyed by target lattice).
    • ledger — a shared-refund aggregator (reads from each lattice’s tally::Refunds, commits SharedRefunds keyed by origin member).

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)
    || OrganismRef.stable_id(intents)
    || OrganismRef.stable_id(ledger)
    || (no ticket issuer)
  )

  ATLAS_ROOT      = COALITION_ROOT.derive("module").derive("atlas")
  ALMANAC_ROOT    = COALITION_ROOT.derive("module").derive("almanac")

  // Composite organisms derive independently of the coalition.
  INTENTS_ID      = blake3("organism|" || SCHEMA_VERSION_U8 || "|intents"
                           || [ethereum, unichain, base]
                           || intents_content
                           || intents_acl)
  LEDGER_ID       = blake3("organism|" || SCHEMA_VERSION_U8 || "|ledger"
                           || [ethereum, unichain, base]
                           || ledger_content
                           || ledger_acl)

  // Per-component committee derivations follow the usual pattern.

A composite organism’s spanned-member set may be a subset of the coalition’s member set. An intents composite organism might span all three lattices while a feed-oracle composite organism spans price-feed.eur and one lattice. Each composite organism 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.
  • Composite-organism operator — the team responsible for one composite organism’s committee members. Composite-organism 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 CoalitionConfig itself. Often coincides with one of the above; does not have to. Has no technical authority over the referenced members or composite organisms.
  • 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 state machine; transitions between steps are stream/collection subscriptions. No arrow represents an atomic multi-Group commit.

  integrator                    organism                   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                  ───► MemberCard updates (any time)

  composite  ──► 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]

  composite  ──► ledger                ───► SharedRefunds[S] committed per origin member

  wallet / searcher ◄──  ledger              refunds + attestations stream (aggregated)
  dashboard        ◄──  atlas                directory of members (for observability)
  correlator       ◄──  almanac              shared tick axis (for cross-member joins)

Two properties of this flow:

  • The slot number remains the foreign key for block- building lattices but is per-member. Slot S on ethereum.mainnet is unrelated to slot S on unichain.mainnet. Composite organisms crossing member boundaries key commits by (member_id, slot) pairs (or (member_id, tick) for non-slotted standalone organisms). If the coalition ships an Almanac, composite organisms may optionally carry the current almanac_tick as an additional alignment key.
  • Each member’s pipeline is unchanged. The intents composite organism injects routed-intent entries into a lattice’s offer input via a subscription, not a cross-Group command. Each offer decides whether and how to include routed intents in its auction. Non- slotted organisms like price-feed.eur continue publishing on their own clock; composite organisms read their ticks as they appear.

Where each composite organism commits

The rule from the builder book — “what decision is the organism actually making at commit time” — carries to composite organisms and modules:

  • atlas commits MemberCard updates. The state machine merges operator-submitted cards (signed by the contributing per-member operator, or by the coalition operator in single-operator coalitions) into the Atlas map.

  • almanac commits a monotonic tick. The state machine runs a deadline-driven Raft round; winner’s tick becomes Ticks[K+1].

  • intents commits a routed-intents entry per slot per target lattice. State machine reads cross-chain intents from each spanned lattice’s UnsealedPool, applies the routing policy, commits {member_id, slot, intents[]} into RoutedIntents.

  • ledger commits a shared-refund entry per origin member per slot. State machine reads each spanned lattice’s tally::Refunds, performs attribution across origin members, and commits {origin_member, slot, shares[]} into SharedRefunds.

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 composite organisms and modules:

  • Per-member subscription fan-in. Gossip between committee members about per-member 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 member upgrades

Member identity splits into a stable id and a content hash; each moves on a different cadence.

  • Member internal rotation (stable id unchanged, content hash bumps). TDX Measurements rotation or ACL change. Invisible to COALITION_ROOT. Commissioned composite organisms that pin content hash redeploy; composite organisms that pin stable id only continue as-is. The coalition publishes an advisory if the change matters to downstream components, but the CoalitionConfig does not change.

  • Member retirement (stable id changes). The per- member operator publishes a new identity. Coalitions that reference this member must re-publish their CoalitionConfig with the new stable id. Every module’s identity bumps because COALITION_ROOT has changed; composite organisms do not re-derive unless they themselves span the retired member and pin its reference.

This is a material clarity win over a design where every member change ripples into composite-organism identity: a coalition referencing ten members rotating TDX monthly sees module identity stable unless a retirement happens.

A coalition operator insulating integrators from member 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 composite organisms. Indicative, not binding.

ComponentCommittee members (v1)Stream bytes / eventNotable bonds
Per lattice (×3)see builder sizingsee builder sizingsee builder sizing
price-feed.eursee organism sizingsee organism sizingcommittee + publishers
atlas (module)3 membersO(members × card size)committee + coalition op
almanac (module)3–5 membersO(1) per tickcommittee only
intents composite3–7 TDX membersO(intents × lattices)committee + each lattice
ledger composite3–5 membersO(refunds)committee + each lattice

“v1” here means the coalition-level Phase 1 shape. Phase 2 adds more composite organisms as cross-member problems arise; Phase 3 introduces multi-operator composite organisms where committee members span organisations.

What this chapter deliberately does not cover

  • Per-organism state machines. Each organism owns its own spec in its own crate once commissioned.
  • Per-organism 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 composite organisms or organism categories. See topology-intro — What a coalition is not.
  • Deferred-primitives space (enforcement, taxation, judiciary). Deferred; see topology-intro — Fixed shapes, open catalogs.

Basic services

audience: contributors

Atlas, Almanac, Chronicle, Compute, Randomness.

A basic service (also called a module) is a coalition-scoped organism whose shape is specified once in the blueprint so every instance means the same thing across coalitions. Each is derived under COALITION_ROOT.derive("module").derive(name) and exposes only mosaik primitives — Stream, Group, and Collection variants (see docs.mosaik.rs). The blueprint adds no types for a module beyond its OrganismConfig.

None of the five is mandatory. A coalition may ship any subset. If a coalition ships a service named “Atlas”, it must have the shape on this page; a service named “Atlas” with a different shape is a bug, not a variant.

Two of the five — Compute and Randomness — have an additional market-for-supply structure: the module’s committee schedules and commits, but the work is discharged off-module by separate providers that compete to register. Atlas, Almanac, and Chronicle do their own work inside the committee.

Fix the shapes. Leave the catalogues open.

Atlas

Directory of the coalition’s members. Every coalition bigger than a single member benefits from one; cheapest module to operate.

Public surface: Map<MemberId, MemberCard> where MemberCard carries the member’s role, stable id, endpoint hints, ticket-issuance root, and any TDX Measurements pins.

OrganismConfig folds the coalition root (via .derive("module").derive("atlas")), the ordered list of members it catalogues, and the Atlas committee’s ACL.

Trust shape: majority-honest, typically non-TDX.

When to ship: almost always. When to skip: single-member coalitions.

Almanac

Shared clock beacon. Composite organisms correlating facts across members need one.

Public surface: Stream<AlmanacTick> where each tick carries a monotonic seq: u64 and a per-member timestamp vector as an advisory correlation hint.

OrganismConfig folds the coalition root under "almanac", the tick cadence, and the committee’s ACL.

Trust shape: majority-honest. Ticks are ordering markers; the timestamp vector is not a cryptographic timestamp.

When to ship: more than one cross-member correlator. When to skip: members that correlate on their own clocks only.

Chronicle

Tamper-evident audit log of coalition actions: publications, rotations, retirements, membership changes, module upgrades.

Public surface: Stream<ChronicleEntry> where each entry carries a monotonic seq, a ChronicleKind, the coalition fingerprint at commit time, a structured payload, and per-member signatures in addition to the committee’s quorum signature. The committee also periodically commits a blake3 digest of the stream to an external settlement contract.

OrganismConfig folds the coalition root under "chronicle", the committee ACL, the entry schema version, and the external anchor contract address.

Trust shape: tamper-evidence holds while either the on-chain anchor path is uncompromised, or at least one honest ex-member’s signed archive survives. Retroactive rewriting requires compromising both.

When to ship: multi-operator coalitions; coalitions with contested lineage; coalitions needing externally verifiable provenance.

Compute

Scheduler and registry for compute grants. Coalition members submit requests; the committee matches them to registered providers; providers run the workloads and commit usage logs.

Compute is the book’s reference case for a market-for-supply basic service. The module commits the match. The compute itself runs on a separate provider. The split is deliberate: the coalition’s trust boundary ends at the scheduling commit; the provider is bonded separately through mosaik’s normal ACL.

Public surface:

  • Stream<ComputeRequest> — write-side; coalition members submit here.
  • Collection<RequestId, ComputeGrant> — the committee’s scheduled allocations.
  • Collection<ProviderId, ProviderCard> — registered providers.
  • Stream<ComputeLog> — provider-committed usage after a workload runs.

The data types:

pub struct ComputeRequest<'a> {
    pub requester:   MemberId,
    /// Stable id of the workload organism the
    /// requester wants run. The organism's
    /// Config.content already pins everything the
    /// provider needs to run it — no separate
    /// manifest.
    pub workload:    UniqueId,
    /// Optional content-hash pin, when the requester
    /// wants one specific build.
    pub pin:         Option<UniqueId>,
    pub duration_sec: u32,
    /// Opaque settlement evidence the requester
    /// chose. The module stores the hash and
    /// verifies nothing about it; settlement rails
    /// live off-module.
    pub settlement:  UniqueId,
    pub deadline:    AlmanacTick,
}

pub struct ComputeGrant<'a> {
    pub request_id:    UniqueId,
    pub provider:      MemberId,
    pub endpoint_hint: EndpointHint<'a>,
    pub bearer_pointer: UniqueId,
    pub content_hash:  UniqueId,
    pub valid_from:    AlmanacTick,
    pub valid_to:      AlmanacTick,
    pub expected_mrtd: Option<Mrtd>,
}

pub struct ComputeLog<'a> {
    pub grant_id: UniqueId,
    pub provider: MemberId,
    pub window:   AlmanacRange,
    pub usage:    UsageMetrics,
    pub evidence: Option<EvidencePointer<'a>>,
}

OrganismConfig folds the coalition root under "compute", the committee ACL, and an optional provider_reputation: OrganismRef the module consults at clearing.

State machine: three commands — SubmitRequest, CommitGrant, AppendLog.

Trust shape: majority-honest committee for scheduling. Provider-level trust is the provider’s own TicketValidator; the module does not vouch. A malicious provider that accepts a grant and never runs the image is detectable by the requester’s outputs never appearing; a reputation organism orthogonal to the module scores it.

When to ship: coalitions with members — AI agents in particular — that need programmatic compute acquisition. When to skip: coalitions whose members bring their own compute out of band.

Not a compute provider. Not a payment rail. Not a guarantee of provider honesty. Not a cross-coalition marketplace.

Randomness

Scheduler and commit authority for a coalition’s randomness beacon. Like Compute, the module commits the values but does not produce them; the actual randomness comes from a registered beacon provider whose identity the module publishes with each round.

Public surface:

  • Stream<BeaconTick> — the authoritative beacon sequence.
  • Collection<ProviderId, ProviderCard> — registered providers (reuses the Compute ProviderCard shape; the card’s content declares which beacon scheme the provider runs).
pub struct BeaconTick {
    pub round:        u64,
    pub provider:     MemberId,
    pub value:        [u8; 32],
    /// Scheme-specific proof (BLS signature, VRF
    /// proof, external-anchor inclusion proof, TDX
    /// quote). The committee verifies the proof
    /// against the provider card's declared scheme
    /// before committing the tick.
    pub proof:        Vec<u8>,
    pub committed_at: AlmanacTick,
}

Consumers that want a per-round targeted draw derive it locally:

  draw = blake3(beacon_value || domain_separator)

No BeaconRequest, no BeaconGrant, no challenge-stream surface: a consumer who suspects a round was biased files a ChronicleEntry and unpins the provider from their own validator.

OrganismConfig folds the coalition root under "randomness", the committee ACL, and the set of beacon-scheme families the module admits (threshold-bls, vrf, external, tdx-attested as operator-declared tags).

State machine: two commands — RegisterProvider and CommitBeacon.

Trust shape: the module’s scheduling and commit integrity is majority-honest committee. The beacon’s unbiasability is inherited from the provider’s declared scheme; the module verifies the proof at commit time but does not add cryptographic guarantees beyond what the scheme itself provides. Consumers admitting weak schemes get weak randomness.

When to ship: members need verifiable randomness (coordination markets, agent experiment allocators, commit-reveal auctions, leader-election committees). When to skip: randomness needs are cosmetic, or satisfied by an external beacon consumers bond to directly.

Not a beacon producer. Not a proof of unbiasability. Not a payment rail. Not a cross-coalition beacon.

Retirement markers

A cross-cutting primitive every composite organism, module, and coalition supports. Before committee shutdown, the component commits a RetirementMarker on its own public stream so consumers upgrade cleanly rather than receiving ConnectTimeout.

pub struct RetirementMarker<'a> {
    pub effective_at: RetirementInstant,
    pub replacement:  Option<ComponentRef<'a>>,
}

A retirement marker is the last commit on the stream. A Chronicle entry records it at the coalition level as ChronicleKind::OrganismRetired or ChronicleKind::ModuleRetired.

Deriving a module’s identity

Every module is an organism; the derivation folds the coalition root under a "module" segment:

  ATLAS_ROOT      = COALITION_ROOT.derive("module").derive("atlas")
  ALMANAC_ROOT    = COALITION_ROOT.derive("module").derive("almanac")
  CHRONICLE_ROOT  = COALITION_ROOT.derive("module").derive("chronicle")
  COMPUTE_ROOT    = COALITION_ROOT.derive("module").derive("compute")
  RANDOMNESS_ROOT = COALITION_ROOT.derive("module").derive("randomness")

  <module>_committee = blake3(
      <module>_root
      || ordered member references (if any)
      || module_content_fingerprint
      || module_acl_fingerprint
  ).derive("committee")

The "module" segment distinguishes coalition- scoped components from commissioned composite organisms (which derive without a coalition root).

CoalitionConfig helpers

A coalition’s OrganismRef for each shipped module is stored in a dedicated field on CoalitionConfig, not a typed container. The coalition meta-crate exposes direct accessors:

impl CoalitionConfig<'_> {
    pub const fn atlas(&self)      -> Option<&OrganismRef<'_>>;
    pub const fn almanac(&self)    -> Option<&OrganismRef<'_>>;
    pub const fn chronicle(&self)  -> Option<&OrganismRef<'_>>;
    pub const fn compute(&self)    -> Option<&OrganismRef<'_>>;
    pub const fn randomness(&self) -> Option<&OrganismRef<'_>>;
}

A coalition that does not ship a module leaves the field None; a later version can ship it without breaking integrators that did not consult the field before.

Deliberately unspecified

  • Chronicle retention policy, storage layout, and anchor cadence — operator-configured.
  • Almanac tick cadence.
  • Atlas metadata schema beyond the required fields.
  • The set of scheme-family tags a Randomness module admits.
  • Whether a module is required for any downstream composite organism. Composite organisms that need a module declare the dependency in their own OrganismConfig.
  • Compute settlement evidence format. The module stores a hash; how it is verified lives with whichever rail the coalition uses (on-chain payment contract, reputation card, credit token).
  • Deferred-primitives-space extensions — out of scope. See deferred-primitives pressure.

Cross-references

Ticket issuance

audience: contributors

A coalition may optionally publish a coalition-scoped ticket issuer — a mosaik ticket issuance root whose tickets components may choose to recognise. This page specifies the shape and the composition.

The primitive is deliberately thin. It is not a policy engine; it is not a state machine with Request/Grant semantics; it is not the former Passport spec. It is a mosaik ticket issuance root, folded into CoalitionConfig, with one composition discipline: components opt in.

Shape

#[non_exhaustive]
pub struct TicketIssuerConfig<'a> {
    /// Issuer role / name folded into the derivation.
    pub name: &'a str,
    /// The issuer's ACL composition — how committee
    /// members rotate, which operators run issuance, etc.
    pub acl: AclComposition<'a>,
}

pub const fn coalition_ticket_issuer_root(coalition_root: UniqueId) -> UniqueId {
    coalition_root.derive("tickets")
}

TICKETS_ROOT = COALITION_ROOT.derive("tickets"). The issuer’s TicketIssuerConfig is folded into COALITION_ROOT as the final ordered element after COA_ORGANISMS.

How components opt in

Any organism (standalone, composite, or module) that wants to recognise tickets issued by the coalition-scoped issuer includes TICKETS_ROOT in its own TicketValidator composition:

let validator = TicketValidator::new()
    .recognise_issuer(ETH_SUPERCHAIN.ticket_issuer_root()?)
    .require_ticket(Tdx::new().require_mrtd(organism_mrtd));

No component is required to. A composite organism designed to be referenced by many coalitions typically does not pin any coalition’s issuer, precisely because pinning a coalition would tie its identity to that coalition. A module shipped specifically for one coalition may pin it.

Trust shape

The trust shape is inherited from mosaik’s TicketValidator composition. This page introduces no new primitives:

  • Tickets issued under TICKETS_ROOT are ordinary mosaik tickets whose issuer identity happens to be coalition- scoped.
  • A component that pins the issuer trusts the coalition operator’s issuance discipline at least as far as they trust the ACL composition on that validator branch.
  • A component that does not pin the issuer ignores its tickets entirely.

Because recognition is per-component and voluntary, there is no protocol channel for the coalition to compel recognition. The coalition operator publishes the issuer root; components individually decide whether to trust it.

When to ship an issuer

  • Shared bonding. A coalition running several composite organisms whose committees cross-bond frequently benefits from a single issuance root rather than N per-organism roots.
  • Multi-operator recognition. A coalition with multiple operators wanting a convenient common issuance root for ad-hoc identities.

When to skip

  • Single-operator coalitions. The coalition operator already issues their own tickets at the organism level; a separate coalition-scoped root is unnecessary indirection.
  • Open ecosystems. A coalition whose intended value is to stay out of bonding decisions ships no issuer.

Rotation

The coalition operator rotates the issuer ACL the same way any ticket-issuing organism rotates: publish a new TicketIssuerConfig (which bumps TICKETS_ROOT via COALITION_ROOT), update CoalitionConfig to the new issuer, announce through the change channel, and if the coalition ships a Chronicle, record the rotation as ChronicleKind::TicketIssuerRotated.

Components that pin the old root see new tickets fail validation; they pin the new root on their next upgrade. Components that don’t pin at all are unaffected.

Cross-references

Composite organisms

audience: contributors

A composite organism is an organism whose Config fingerprint folds two or more member references (lattice references, OrganismRefs, or a mix) and whose public surface coordinates across the referenced members. “Composite” is a role-name convention, not a type: the organism follows the same OrganismRef shape as any other. This chapter specifies when to commission one and how its Config preimage works.

Modules (Atlas, Almanac, Chronicle) are, mechanically, organisms too; their shapes are specified once in basic services. They differ from general organisms in one way: modules derive under a coalition root, while commissioned organisms derive independently of any coalition. The generic organism discipline below applies to both; the derivation difference is called out where it matters.

The reader is assumed to have read Designing coalitions on mosaik and Anatomy of a coalition.

Definition

A composite organism is an organism in every sense the zipnet and builder books use the word. It has:

  • one Config fingerprint;
  • a narrow public surface (one or two named primitives);
  • a TicketValidator composition gating bonds;
  • typed Organism::<D>::verb(&network, &Config) free- function constructors;
  • a deterministic state machine inside a mosaik Group.

What distinguishes a composite organism from a standalone organism:

  • Its content fingerprint folds in multiple member references — the ordered set of members whose public surfaces it reads from (or writes to).
  • Its state machine’s commits are a function of inputs drawn from more than one member’s public surface, and serve consumers on more than one member.

A composite organism is not a seventh lattice organism; it is not part of any lattice’s identity derivation; no per-member operator has to know what composite organisms reference their member. A composite organism is independent of any coalition that references it — its committee, state machine, and log are shared across coalition references.

When to commission one

Commission a composite organism when all three of the following hold.

  1. The aggregated fact is itself a commit. If what you need can be computed ad hoc by an integrator across N member handles, it does not need a composite organism. If multiple downstream consumers would each have to repeat the same aggregation, or if the aggregation is itself the input to yet another organism, the commit pays for itself.

  2. The inputs span more than one member. A composite organism that reads only from one member is a single-member organism in disguise; it belongs as a standalone organism (or inside that member’s own composition, if the member is a lattice).

  3. The trust model is coherent across the inputs. A composite organism inherits the worst-case trust assumption of the member inputs it reads. If you cannot name the cross-member trust shape (e.g. “majority-honest across each lattice’s unseal committee, t-of-n on the oracle organism, plus majority-honest composite-organism committee”), you have not finished the design.

When any of the three is false, the right answer is one of:

  • A cross-member integrator (Shape 1 in builder’s cross- chain chapter, generalised to any mix of members).
  • An in-lattice organism that reads a sibling lattice’s public surface (Shape 2).
  • A new standalone organism.
  • A new organism inside an existing lattice.

Composite organism versus cross-member integrator

TraitIntegrator-spans-membersComposite organism
Runs a Raft committeenoyes
Commits to a state machinenoyes
Admits other peers via ACLnoyes
Consumes multiple membersyesyes
Produces a reusable commitno (per-integrator in-memory join)yes (public surface consumers can read)
Cost to stand upa driver in the integrator’s agenta crate, a committee, an ACL
Availabilitybounded by one agentcommittee-level (Raft majority)
Trust assumptionintegrator’s ownexplicit, compositional

Heuristic: if three different integrators would all perform the same aggregation, it is a candidate composite organism. If exactly one integrator needs it, keep it in the agent.

The Config fingerprint

A composite organism’s Config folds in:

#[non_exhaustive]
pub struct OrganismConfig<'a> {
    /// Role name: "intents", "ledger", "market",
    /// "correlate", … For modules:
    /// "atlas", "almanac", "chronicle".
    pub name: &'a str,

    /// Ordered set of block-building lattices whose
    /// public surfaces this organism reads or writes.
    pub lattices: &'a [LatticeConfig<'a>],

    /// Ordered set of standalone organisms whose public
    /// surfaces this organism reads or writes. Same
    /// story as `lattices` above, for non-lattice
    /// members.
    pub organisms: &'a [OrganismRef<'a>],

    /// State-affecting parameters specific to this
    /// organism. E.g. an intent router's policy
    /// constants, a shared ledger's attribution model,
    /// an almanac's tick cadence.
    pub content: ContentParams<'a>,

    /// TicketValidator composition gating committee
    /// admission.
    pub acl: AclComposition<'a>,
}

impl OrganismConfig<'_> {
    pub const fn organism_id(&self) -> UniqueId { /* ... */ }
}

Identity derives from (name, spanned members, content, acl) with no coalition root folded in:

  ORGANISM(cfg) = blake3(
                      "organism|"
                      || SCHEMA_VERSION_U8
                      || "|" || name
                      || ordered spanned LatticeConfig references
                      || ordered spanned OrganismRef references
                      || content_fingerprint
                      || acl_fingerprint
                    )

A composite organism can therefore be referenced by N coalitions; its committee, state machine, and log are shared across those references. Operators wanting two independent deployments deploy two composite organisms with different content or different ACLs — the cryptographic gate is the fingerprint, not coalition scope.

For modules the derivation is different — they derive under a coalition root (see basic services — Deriving a module’s identity). The public surface, state-machine discipline, and OrganismConfig fields are otherwise identical.

Public surface

Composite organisms follow the narrow-public-surface discipline without modification. Guidelines for picking the surface:

  • Key every commit by (member_id, slot) or (member_id, tick) when the organism is per- clock-event per-origin-member. member_id is the 20-byte truncated prefix of the member’s blake3 fingerprint. Integrators that join commits across composite organisms need this key.
  • Separate routing and attestation. If your composite organism both routes inputs (a write-side stream) and commits the routing outcome (a read-side collection), keep the two primitives named. Do not fold them into one.
  • Expose attestations separately when the commit carries an attestable signature. Integrators that pull attestations to on-chain settlement contracts want the signature surface distinct from the routing surface.
  • If your composite organism depends on a module, declare it. A correlator that aligns to Almanac ticks reads Almanac and commits under (member_id, almanac_tick) keys; state that in the crate’s composition-hooks doc and in the OrganismConfig.content parameters (since the alignment is state-affecting).

A design wanting three or more public primitives is likely two composite organisms.

State machine shape

Inside the composite organism’s Group, the state machine is an ordinary mosaik StateMachine<M>. It differs from a standalone organism’s state machine only in what its inputs look like: driver code outside the state machine subscribes to public surfaces on each spanned member and feeds observed facts into the composite organism’s group via group.execute(...).

Template for a composite-organism driver:

// Inside the composite organism's node crate, role: committee member.
loop {
    tokio::select! {
        // Per-member subscriptions the composite organism reads from.
        ev = lattice_a_subscription.next() => {
            let evidence = build_evidence_for_a(ev);
            organism_group.execute(OrganismCmd::ObserveLatticeA(evidence)).await?;
        }
        ev = lattice_b_subscription.next() => {
            let evidence = build_evidence_for_b(ev);
            organism_group.execute(OrganismCmd::ObserveLatticeB(evidence)).await?;
        }
        ev = organism_c_subscription.next() => {
            let evidence = build_evidence_for_c(ev);
            organism_group.execute(OrganismCmd::ObserveOrganismC(evidence)).await?;
        }
        // Optional: align to a coalition's Almanac the
        // composite organism has been configured to track.
        ev = almanac_subscription.next() => {
            let tick = /* ... */;
            organism_group.execute(OrganismCmd::AdvanceTick(tick)).await?;
        }
        // Composite organism's own timers, per its state machine.
        _ = apply_deadline.tick() => {
            organism_group.execute(OrganismCmd::Apply).await?;
        }
    }
}

Rules:

  • Observations are evidence, not authority. The Observe* commands carry a pointer to the upstream member commit (member id, slot or tick, commit hash). The composite organism’s state machine validates the pointer against the member’s public surface on replay.
  • Applies are pure functions. apply(OrganismCmd::Apply) reads the accumulated observations and emits the composite organism’s commit. It does not make new cross-member reads inside apply; reads belong to the driver.
  • No cross-Group calls inside apply. Same discipline as every organism.

ACL and attestation

A composite organism’s TicketValidator composition can include:

  • Per-member readership tickets. A composite organism reading from lattice A’s unseal::UnsealedPool or from an oracle organism’s feed is an integrator of that member from the member’s perspective. Committee members must hold tickets the per-member operator issues, same as any other integrator reading that surface.
  • TDX attestation. If the composite organism sees cleartext order flow or otherwise-sensitive data, the committee members are almost always required to run an attested TDX image. .require_ticket(Tdx::new().require_mrtd(organism_mrtd)) is the standard line.
  • Optional coalition-scoped issuer recognition. If a composite organism expects to be used predominantly under one coalition whose ticket issuer is stable, it may include that issuance root in its validator composition — a choice made on the composite organism’s side, not imposed by the coalition. See ticket issuance.

Failure modes

A composite organism has more failure modes than a standalone organism because its inputs are multi-operator:

  • One spanned member stalls. The composite organism’s state machine must decide whether to commit with partial evidence (degrading quality but preserving liveness) or to stall that slot pending the missing member (preserving quality but sacrificing liveness on the slot). This is a per-organism choice; document it in the composition contract.
  • One spanned member’s stable id changes. The composite organism’s Config folds that reference; a change means the composite organism must be redeployed. Until it is, the composite organism’s subscriptions to the old member simply stop producing events.
  • One spanned member’s content hash changes (if pinned). Same as above but limited to composite organisms that chose to pin content — stable-id-only pinners are unaffected.
  • Composite-organism committee loses majority. Same failure mode as any mosaik Raft group. Liveness is lost; integrity is intact.
  • Spanned member’s ACL changes. If a per-member operator revokes the ticket committee members hold, the composite organism loses read access to that member’s public surface. Negotiated out of band; there is no technical recourse.

Composition patterns worth naming

Three patterns recur often enough to name. These are patterns, not required composite organisms; modules are the specified shapes.

Intent-router pattern

A composite organism whose state machine commits per-slot routed intents keyed by (target_lattice_id, slot). Reads cleartext from each spanned lattice’s unseal::UnsealedPool; commits a RoutedIntents collection each target lattice’s offer subscribes to. Trust shape: TDX-attested committee plus t-of-n threshold on the cross-member cleartext channel.

The builder book’s Shape 3 bridge organism is an intent- router pattern seed.

Shared-ledger pattern

A composite organism whose state machine aggregates per-lattice tally::Refunds into a cross-origin-member attribution set, committed as SharedRefunds and SharedAttestations. Trust shape: majority-honest composite-organism committee plus the per-member trust shape of each spanned tally. An on-chain settlement contract verifying a SharedAttestation verifies both the composite organism’s signature and the underlying per-lattice tally::Attestation referenced as evidence.

Integrators needing one refund feed across chains bind the composite organism; integrators concerned with a single chain bind that lattice’s tally directly. Both paths coexist.

Cross-feed correlator pattern

A composite organism that pairs ticks from two or more oracle organisms (or more generally, two or more non-slotted standalone organisms), committing correlated values under (member_id, almanac_tick) when a coalition referencing the composite organism ships an Almanac and the composite organism opts in, or under (member_id, timestamp_bin) otherwise. Trust shape: majority-honest composite-organism committee plus the signing assumptions of each upstream oracle.

Other patterns worth naming (non-block-building)

The three patterns above originate in block-building. Other domains will yield more. Sketches:

  • Attestation aggregator. A composite organism that folds TDX Measurements quotes from multiple attestation organisms across vendors or regions into a single attested membership set.
  • Coordination-market organiser. A composite organism that runs an allocation auction where inputs come from several independent signal organisms and outputs drive several independent downstream members.
  • Cross-DA committer. A composite organism that commits a combined availability proof over two or more DA shards.

Each is an OrganismConfig whose lattices slice may be empty and whose organisms slice names the upstreams.

Checklist mirror

The commissioning checklist in topology-intro — Checklist for commissioning a new composite organism applies verbatim. This page is the reference; the topology-intro page is the forcing function when commissioning one.

Cross-references

  • topology-intro — why this rung exists.
  • basic-services — the three specified module shapes plus retirement markers.
  • ticket-issuance — the optional coalition-scoped issuance root.
  • architecture — where composite organisms sit in one example coalition.
  • composition — the subscription graph that members and composite organisms share.
  • atomicity — what composite organisms deliberately do not guarantee.
  • threat-model — how a composite organism’s trust assumption composes with the spanned members’.

Composition — members and organisms in a coalition

audience: contributors

Architecture maps composite organisms and members onto one example coalition. Composite organisms specifies the composite-organism shape. Basic services specifies Atlas, Almanac, and Chronicle. This chapter shows the wiring: which public surface each composite organism subscribes to on each spanned member, how the subscription graph grows as composite organisms and modules are added, and what fails where when an upstream stalls.

The wiring is deliberately weak. No cross-Group atomicity, no shared state across members, no global scheduler. Members and organisms react to each other’s public commits via mosaik’s when() DSL and Collection / Stream subscriptions. This is the composition model at every rung.

Two keys: member id and clock event

Every commit in every block-building lattice is keyed by slot (see builder composition). Every commit in a standalone organism is keyed by that organism’s own clock event — a slot, a tick, a round, a sequence number. A coalition adds the member id as an outer key on every cross-member fact.

The member_id used as a key in cross-member commits is the first 20 bytes of the member’s blake3 stable-id fingerprint. The full 32-byte value lives in Atlas cards and in evidence pointers. The 20-byte truncation gives a compact key that matches the mental model readers bring from other ecosystems; collision resistance remains more than sufficient at this rung.

Concretely:

  • Intra-member commits continue to key on their own clock alone (no change from the member’s own book).
  • Composite-organism commits that fan-out to multiple target members key on (target_member_id, target_clock_event).
  • Composite-organism commits that fan-in from multiple origin members key on (origin_member_id, origin_clock_event).
  • An integrator joining commits across a composite organism and the members the composite organism touches keys on (member_id, clock_event) everywhere.
  • When a coalition ships an Almanac the composite organism has opted into, the composite organism may additionally carry almanac_tick as an alignment key for cross-member joins where the members’ native clocks are not commensurate.

The 20-byte member_id is stable — it never changes for a given member deployment. A member retirement yields a new stable id and is therefore a new member id for every coalition that adopts it.

The subscription graph

Each arrow is a subscription. The downstream component watches the upstream’s public collection or stream and reacts in its own state machine. No arrow represents atomic cross-Group commit. Dashed boxes are composite organisms; the oracle box on the left is a standalone organism.

   integrators
   (wallets,
    searchers)
        │
        ├──► zipnet[L1]:Submit ────► Broadcasts[L1] ──► UnsealedPool[L1] ─┐
        │                                                                  │
        ├──► zipnet[L2]:Submit ────► Broadcasts[L2] ──► UnsealedPool[L2] ─┤
        │                                                                  │
        └──► offer[L1]:Bid / offer[L2]:Bid                                 │
                                                                            │
   price-feed.eur ──► Price[tick]                                          │
                                                                            │
   almanac     ──► Ticks[K]                                                │
        │                                                                   │
        └──────────── referenced by composite organisms for alignment ──┐     │
                                                                    ▼     │
                                                       ┌────────────────── ┘
                                                       ▼
                                          ┌───────────────────────┐
                                          │ intents (composite)   │
                                          │ reads UnsealedPool[*] │
                                          │   + price-feed.eur    │
                                          │ commits RoutedIntents │
                                          └───────────────────────┘
                                                       │
                      RoutedIntents[L1,S] / RoutedIntents[L2,S]
                                                       ▼
                       offer[L1]:AuctionOutcome     offer[L2]:AuctionOutcome
                                 │                            │
                         atelier[L1]:Candidates       atelier[L2]:Candidates
                                 │                            │
                         relay[L1]:AcceptedHeaders    relay[L2]:AcceptedHeaders
                                 │                            │
                         tally[L1]:Refunds            tally[L2]:Refunds
                                 │                            │
                                 └────────────┬──────────────┘
                                              ▼
                                   ┌──────────────────────────┐
                                   │ ledger (composite)       │
                                   │ reads Refunds[*]         │
                                   │ commits SharedRefunds    │
                                   └──────────────────────────┘
                                              │
                                              ▼
                                         integrators

   atlas ──► MemberCards (consumed by dashboards, not coalition pipeline)
   chronicle ──► ChronicleEntries (consumed by auditors, not coalition pipeline)

Read top to bottom:

  1. Wallets submit to each lattice’s zipnet::Submit; searchers submit to each lattice’s offer::Bid. Neither changes from builder.
  2. Each lattice’s zipnet and unseal do their usual work independently. The oracle organism price-feed.eur publishes ticks on its own clock. The Almanac (if shipped) publishes its own tick stream.
  3. The intents composite organism subscribes to every spanned member’s relevant public surface — lattices’ UnsealedPools and, in this example, price-feed.eur’s Price stream. It may additionally subscribe to the Almanac for alignment keys. It observes cross-member intents and commits routed-intents entries per target lattice.
  4. Each lattice’s offer subscribes to the composite organism’s RoutedIntents collection filtered for its own member id. Routed intents are an additional input to the auction, along with the lattice’s own UnsealedPool.
  5. Each lattice’s atelier and relay proceed as in builder.
  6. Each lattice’s tally commits independently.
  7. The ledger composite organism subscribes to every spanned lattice’s tally::Refunds and commits the aggregated SharedRefunds collection.
  8. Integrators read SharedRefunds and per-member surfaces depending on their use case. Dashboards read the Atlas. Auditors read the Chronicle.

Atlas and Chronicle are not on any composite organism’s critical path in this example; they are consumed by dashboards and auditors directly. Modules serve observability and provenance, not the coalition’s data flow.

Subscription code shape

A contributor implementing a composite organism writes a role driver in that composite organism’s crate. The driver is a mosaik event loop multiplexing subscriptions across members and calling group.execute(...) on its own Group. The pattern is identical to any organism driver, fanned out across more member kinds.

// Inside intents::node::roles::committee_member.
//
// `lattices` and `organisms` are the ordered sets of
// member references this composite organism spans,
// sourced from self.config.lattices and
// self.config.organisms.
loop {
    tokio::select! {
        // One subscription per spanned lattice's UnsealedPool.
        ev = pool_a.when().appended() => {
            let round = pool_a.get(ev).expect("appended implies present");
            let intents = extract_cross_chain_intents(&round);
            self.group.execute(IntentsCmd::ObservePool {
                member_id: lattice_a_id,
                slot: round.slot,
                intents,
            }).await?;
        }
        ev = pool_b.when().appended() => {
            // ... same shape
        }
        // One subscription per spanned standalone organism.
        ev = price_feed_eur.when().appended() => {
            let tick = price_feed_eur.get(ev).unwrap();
            self.group.execute(IntentsCmd::ObservePrice {
                member_id: eur_feed_id,
                tick: tick.seq,
                price: tick.value,
            }).await?;
        }
        // Optional: align to a coalition's Almanac.
        ev = almanac.when().appended() => {
            let t = almanac.get(ev).unwrap();
            self.group.execute(IntentsCmd::AdvanceAlmanacTick(t.seq)).await?;
        }
        _ = self.apply_clock.tick() => {
            // Per-slot deadline: seal the routing decision.
            self.group.execute(IntentsCmd::SealSlot).await?;
        }
    }
}

Every observed event carries enough evidence ((member_id, clock_event, commit_pointer)) that the state machine can validate it against the member’s public surface during replay.

Apply order across the graph

Within one organism’s Group, mosaik’s Raft variant guarantees every committee member applies commands in the same order. Across composite organisms, and across members, no such guarantee exists. The coalition layer relies on the same two properties the builder layer does, scaled up:

  1. Monotonicity by key. Within any component, commits for key (C, K+1) are not applied before (C, K). The component’s state machine enforces this per- member in its apply handler.
  2. Eventual consistency by subscription. A downstream component’s driver observes every upstream commit eventually, because mosaik collections are append-only and readers converge.

Together these are enough to reconstruct a consistent per-member per-clock-event view across the whole coalition without global atomicity. An integrator wanting “the canonical decision for member C, clock event K, across members and composite organisms” reads each component’s per-(C, K) commit independently and joins on the key.

When an upstream stalls

Failure propagation is a small matrix. Rows are the failing component; columns are downstream components’ observable behaviour.

Upstream failsSame-member downstreamsComposite organisms that read this memberOther members
lattice organismsee builder compositiondegraded — partial evidence per specunaffected
standalone organismsee that organism’s own bookdegraded — partial evidence per specunaffected
member stable id bump (retirement)in-member consumers re-pincomposite organism must redeploy against new stable idunaffected
member content hash bumpin-member consumers re-pin if they pinnedcomposite organisms pinning content redeploy; stable-id-only pinners are unaffectedunaffected
composite organism stallsno effect (members don’t depend on composite organisms for their own pipeline)downstream composite-organism consumers see no new commitsunaffected
module stallsno effect (members don’t depend on modules)composite organisms aligned to this module see delayed/degraded commitsunaffected
composite-organism committee crosses thresholdno effectbad commits possible (integrity lost); on-chain settlement is the final arbiterunaffected
coalition operator retires coalitionno technical effect (members continue)modules under retired coalition emit retirement markers, then stopunaffected

Two properties fall out, mirroring builder’s:

  • Upstream failures degrade downstream outputs; they do not corrupt them. A missing UnsealedPool[L1, S] narrows the intents composite organism’s commit for that slot; the commit itself remains well-formed.
  • The pipeline is drainable per member. Failures on one member do not block the coalition’s other members. Each member’s pipeline is local; each composite organism applies what it observes.

What the coalition composition contract guarantees

Given the full commit logs of every member and every composite organism the coalition references:

  • Deterministic replay per (member_id, clock_event). Anyone can recompute each component’s per-(C, K) decision and cross-check composite-organism commits against the member inputs they folded in.
  • Independent auditability. A composite organism’s commit carries evidence pointers to the member commits it depends on. A consumer that trusts the members can verify a composite organism’s commit without trusting the composite organism’s committee, as long as the evidence pointers resolve.
  • No silent corruption across coalitions. A member referenced from multiple coalitions is still one member; its commit log is one log. Different coalitions reading the same member see the same facts. A composite organism referenced from multiple coalitions is still one composite organism; its commit log is one log.

What the contract does not guarantee

  • Atomic all-or-nothing commits across members. Already refused. An integrator reading a composite organism’s commit and the spanned members’ commits must tolerate differing commit wall-clock times.
  • Cross-coalition coordination. Coalitions coexist, they do not coordinate. If a cross-coalition commit is genuinely needed, the answer is a composite organism that spans the relevant members directly — which both coalitions may reference independently.
  • Bounded end-to-end latency. As in builder: if a composite organism stalls, downstream consumers never see its next commit. No composite-organism-level timeout triggers a dummy commit; operators requiring bounded latency add per-slot deadlines at the composite-organism level.

Contributors implementing a new composite organism

Wiring checklist for a composite organism:

  1. Identify every spanned member’s public surface you subscribe to. Record as ordered slices of member references in your Configlattices, organisms, or both.
  2. Decide whether your commits fan-in, fan-out, or both. Fan-in composite organisms aggregate per-origin-member facts; fan-out composite organisms distribute one fact to multiple target members; some composite organisms do both.
  3. Key every commit by (member_id, clock_event). Never by one alone. Use the 20-byte truncated member id. If your state machine has a natural sub-clock- event cadence, commit at that cadence but carry the owning (member_id, clock_event) pair. If the composite organism opts into a coalition’s Almanac and needs cross-member alignment, also carry almanac_tick.
  4. Write one role driver per Group member role. Keep it as a tokio::select! over the upstream subscriptions (one per member) and your local timers.
  5. Validate evidence on replay. The upstream-event pointers carried in your Observe* commands must be checkable against the member’s public surface during replay; a replay that sees an unresolved evidence pointer must reject the command.
  6. Document your per-member-failure policy. What happens when one spanned member stalls, reorders, or bumps its stable id or content hash — all are operational realities.
  7. Declare dependency on modules. If you require an Almanac for alignment, or consume Chronicle entries, document it.
  8. Document the composition contract in your composite organism’s contributors/composition-hooks.md (per-organism documentation). Update architecture and this page’s subscription graph to include the new composite organism if the example coalition is the right place for it.

Cross-references

Atomicity boundary

audience: contributors

This chapter states what the coalition layer does and does not guarantee about atomicity, supplying one reference page for design reviews of new composite organisms or extensions to the coalition model.

The rules are inherited from zipnet and builder. The coalition layer introduces no new atomicity primitive; it makes the inherited boundary legible one rung higher.

What the coalition layer does not provide

The coalition layer does not provide:

  • Cross-Group atomicity inside a member. Rejected by builder for lattices and by each organism’s own design for standalone organisms. Two organisms commit independently and subscribe to each other’s public surfaces.
  • Cross-member atomicity inside a coalition. Rejected by this blueprint. Two members in the same coalition commit independently and a composite organism subscribes to both.
  • Cross-coalition atomicity. Rejected by this blueprint. Two coalitions coexist on the shared universe and have no shared consensus unit.
  • Multi-organism atomicity. Rejected by this blueprint. Two composite organisms referenced by the same coalition each commit to their own Group; integrators that need joint commits join by key.

The rejection is load-bearing at every rung. Admitting one atomicity primitive at any rung forces every rung below to carry it, collapsing the trust and operational boundaries the rungs were designed to isolate.

What the coalition layer does provide

The coalition layer provides, as a consequence of the composition discipline:

  • Per-component atomicity. Every organism — standalone, composite, or module — commits atomically within its own Group. Mosaik’s Raft variant guarantees single-Group atomicity.
  • Determinism of replay. Given the commit logs of all components the coalition references, each component’s per-key decision is reproducible. The evidence pointers composite organisms carry make cross-component replay legible.
  • Independent auditability. A consumer verifying a composite organism’s commit need trust only the spanned members’ own commit logs (and the composite organism’s committee, to whatever its trust shape permits). They do not need a coalition-wide replay to audit one composite organism’s decision.
  • Provenance (if Chronicle is shipped). Not atomicity, but a record of coalition-level decisions over time: which CoalitionConfigs were published when, which composite organisms were referenced or unreferenced, which modules were added or retired. Audit trail, not atomicity.

What integrators and operators must design around

Three recurring realities.

Partial outcomes across members

An integrator placing paired bundles on two lattices, or correlating an oracle tick with a lattice auction outcome, must tolerate partial observation: member A commits, member B does not. The coalition layer surfaces this, it does not mitigate it. Every integrator driver spanning members carries reconciliation logic (post-bond collateral, on-chain HTLCs, searcher-level risk management, timestamp tolerance windows — whichever matches the domain).

Staggered commits through composite organisms

A composite organism’s commit for (member_id, clock_event) lags the upstream members’ own commits for that event by at least one Raft round inside the composite organism’s committee. Consumers reading both treat the member commit as ground truth and the composite-organism commit as derived aggregation.

Member identity bumps

A member’s stable id changes on retirement; its content hash bumps more often (ACL rotations, TDX Measurements bumps). A coalition that references that member sees its modules re-derive on stable-id bumps (because COALITION_ROOT changes); composite organisms re-derive only when they themselves span the bumped member. During the transition, old and new deployments may coexist. If the coalition ships a Chronicle, the next Chronicle entry records the transition.

Promotion path if atomicity is genuinely required

If a concrete use case forces atomicity across components:

  • If it’s one lattice, two organisms: design a lattice organism that owns both decisions. That is the same answer builder topology-intro gives.
  • If it’s one coalition, two members: design a composite organism that owns both decisions, subscribing to the two members’ relevant public surfaces. The state machine will commit one atomic record per event-pair; the two members themselves still commit independently, but the composite organism’s commit is the authoritative joint fact. HTLC-style commit semantics live inside the composite organism’s state machine, not across members.
  • If it’s two coalitions: the cross-coalition commit is a composite organism folding the relevant member references directly; both coalitions reference that composite organism independently. No cross-coalition consensus is needed because the composite organism is coalition-independent.

In every case the atomicity primitive lives inside one Group, not across Groups. This is the rule the whole ladder obeys.

Cross-references

Threat model

audience: contributors

This chapter states the trust assumptions the coalition layer adds over the builder and zipnet trust models, and describes how per-component trust composes when members (lattices and standalone organisms), composite organisms, and modules are referenced under one CoalitionConfig.

It does not re-derive per-organism trust shapes inside a lattice; those live in builder threat model. It does not re- derive trust shapes for standalone organisms; those live in each organism’s own book. The coalition layer inherits them unchanged. Primitive-level mechanics the trust arguments below lean on — Raft-based majority-honest agreement (mosaik — Raft consensus), peer bonds (mosaik — Bonds & Peer Connections), state-sync for catch-up (mosaik — State Sync & Replay), and deterministic hashing (mosaik — Determinism & Hashing) — are specified upstream and referenced inline where they bite.

Goals and non-goals at the coalition layer

Goals.

  • Trust is strictly compositional. A property of a single member is not weakened by that member being referenced in a coalition. Referencing is ambient; it does not open new channels into the member.
  • Composite-organism commits are independently auditable against the member commits they fold in. A consumer that trusts the spanned members can verify a composite organism’s commit without trusting the composite organism’s committee, up to the composite organism’s own majority-honest bound.
  • Coalition identity is a naming convenience. Code treating a CoalitionConfig fingerprint as authority is misusing it.
  • Modules do not gate. Atlas, Almanac, and Chronicle are services a coalition offers; none is on any member’s critical path for admission or operation. A compromised module can mislead consumers but cannot compel a member.

Non-goals.

  • Cross-coalition confidentiality. Two coalitions coexisting on the shared universe do not get any additional confidentiality over “two services on the shared universe” already get. Mosaik’s ACL and tickets are the only gates.
  • Cross-member atomic integrity. Ruled out at the composition layer. See atomicity.
  • Protection against a malicious coalition operator. A coalition operator can publish a CoalitionConfig referencing any member whose stable id they know, including members whose operators have not consented to the reference. The reference has no technical consequence for the member’s integrity or confidentiality; it is a social or legal matter between operators. The blueprint surfaces the observability required to flag the misuse; it does not prevent it.
  • Protection against deferred-primitives drift. A future proposal promoting a deferred primitive (enforcement, taxation, judiciary) requires its own threat model. The current model assumes opt-in composition only.

The composite organism’s trust composition

Every composite organism’s trust shape is determined by two inputs:

  1. The composite organism’s own committee assumption. Usually majority-honest for integrity, possibly TDX-attested for confidentiality of the cleartext it processes.
  2. The worst-case assumption across the spanned members’ public surfaces it reads. If the composite organism reads cleartext from each spanned lattice’s unseal::UnsealedPool and a signed feed from an oracle organism, it inherits the t-of-n threshold of every spanned unseal committee and the signing-quorum assumption of the oracle organism.

The composed assumption is the conjunction: the composite organism’s guarantee holds while every component’s assumption holds simultaneously. Breaking any one component can at most degrade the composite organism’s output per the weakest component’s failure mode.

Crucially, the composite organism’s trust shape does not include any coalition that references it. A malicious coalition operator cannot weaken a composite organism they merely reference; they can only stop referencing it in their next CoalitionConfig.

Example: the intents composite organism

An intents composite organism reads cleartext from three lattices’ UnsealedPools and commits a per-target- lattice routed-intents commit under a TDX-attested, majority-honest committee.

  • Confidentiality of cross-chain intents to external observers: holds while every spanned lattice’s zipnet any-trust assumption and unseal t-of-n threshold assumption hold and the composite organism’s TDX image is attested.
  • Integrity of the routed commit: holds while the composite organism’s majority-honest committee assumption holds.
  • Availability of routing: holds while at least one of the spanned lattices reaches UnsealedPool for the target slot and a composite-organism majority commits.

Example: the shared-ledger composite organism

A ledger composite organism reads each spanned lattice’s tally::Refunds and commits an aggregated SharedRefunds under a majority-honest committee.

  • Faithfulness of the aggregated attribution: holds while every spanned lattice’s tally majority-honest assumption and the composite organism’s own majority-honest assumption hold. A malicious lattice tally majority can poison the aggregated commit; the on-chain settlement contract receiving SharedAttestations is the final check.
  • Non-duplication of refunds: holds while the aggregation rule is implemented correctly and state- machine-deterministic.

Module trust shapes

Each of the five modules has its own trust shape, summarised here and specified in basic services.

Atlas trust

  • Faithfulness of MemberCard contents: holds while the Atlas committee is majority-honest. A compromised Atlas can publish incorrect endpoint hints or stale TDX Measurements pins. Integrators are expected to cross-check with per-member operators’ own handshake pages; Atlas is a convenience, not a certificate.
  • Confidentiality: N/A; Atlas is public by design.

Almanac trust

  • Monotonicity of ticks: holds while the Almanac committee is majority-honest. A compromised Almanac can skip ticks or delay them, but cannot un-commit previously committed ticks.
  • observed_at timestamp vectors are advisory. A compromised committee can publish ticks with implausible timestamps; consumers should treat the per-member vector as a correlation hint, not a cryptographic timestamp. The vector shape does let consumers compositionally detect single-member clock skew (outlier entries in an otherwise-clustered vector); this is an observability aid, not a security guarantee.

Chronicle trust

  • Tamper-evidence of past entries: holds while at least one of:

    • (a) the on-chain anchor path is uncompromised — the Chronicle committee periodically commits a blake3 digest of the entry stream to the anchor contract declared in ChronicleConfig.content; or
    • (b) at least one honest ex-member’s signed archive survives — every ChronicleEntry carries per-member signatures in addition to the quorum signature, so an honest ex-member’s archive is a cryptographic witness against forgery.

    Retroactive rewriting requires compromising both paths.

  • Completeness of recent entries: majority-honest. A compromised committee can omit entries from being committed; it cannot forge them without being detected, but it can DoS provenance.

Compute trust

  • Scheduling integrity. Holds while the Compute committee is majority-honest. A compromised committee can grant a request to a provider who never runs the image, grant to a wrong provider, or omit grants altogether. It cannot forge a provider’s usage attestation (those are provider-signed) nor steal a requester’s settlement evidence (settlements live off-protocol).
  • Image-hash honesty. A grant commits a specific image post-hash; a TDX-gated grant additionally commits the expected TDX Measurements. The requester verifies the provider is actually running the committed image at workload startup; a provider running a different image fails attestation and the workload aborts.
  • Non-collusion between scheduler and provider. Out of scope. The Compute module commits the match; if the scheduler and a malicious provider collude, the requester’s only recourse is observing that the workload’s outputs never appear and routing to a different provider next time. A reputation organism scoring provider delivery closes the loop.

Randomness trust

  • Scheduling and commit integrity. Holds while the Randomness committee is majority-honest. A compromised committee can skip rounds, delay commits past their target tick, or grant a round to a provider whose card it should have rejected. It cannot forge a beacon value that verifies against an honest provider’s declared public key.
  • Unbiasability inheritance. The beacon’s unbiasability is inherited from the provider’s declared scheme. A coalition admitting a weak scheme (a plain VRF alone) is offering randomness that a malicious provider can bias by withholding unfavourable draws. A coalition admitting only threshold-BLS (t-of-n ≥ 3-of-5) or TDX-attested schemes inherits those schemes’ unbiasability arguments.
  • Challenge path. Suspected bias goes on Chronicle (a signed entry naming the round and the challenger’s evidence); consumers unpin the provider in their own validator. The module has no built-in challenge stream.
  • Non-collusion between scheduler and provider. Out of scope, same as Compute. If the scheduler and a malicious beacon provider collude, the bias is detectable only by consumers’ own cross- verification. A reputation organism scoring provider honesty closes the loop.

Ticket issuance trust

  • Issuance correctness: trust shape inherited from mosaik’s TicketValidator composition. This blueprint introduces no new primitives. A component that recognises the coalition-scoped issuance root trusts the issuer’s ACL composition; a component that does not recognise it is unaffected.

Coalition operator responsibilities

Coalition operators carry a narrow set of responsibilities.

Must do:

  • Publish the CoalitionConfig struct (and the derived fingerprint) as the handshake.
  • Publish every module’s and every coalition-run composite organism’s TDX Measurements if TDX-gated.
  • Publish every coalition-commissioned standalone organism’s TDX Measurements that is TDX-gated. If the organism is operated by a different team, that team publishes its own TDX Measurements and the coalition operator re-publishes for convenience.
  • Document the set of members and composite organisms referenced, including a pointer to each per-member operator’s and per-composite-organism operator’s handshake page.
  • State explicitly which modules the coalition ships and which it does not. Silence is ambiguous.
  • Notify integrators when a referenced member’s stable id bumps and publish the updated CoalitionConfig promptly.

What a compromised coalition cannot do

Regardless of how many modules a coalition operator runs maliciously:

  • Cannot change a referenced member’s or referenced composite organism’s commits. Each component’s commit log is authoritative in its own Groups. A compromised module cannot forge a commit belonging to another component.
  • Cannot mint money. Same argument as builder: on- chain settlement contracts enforce the evidence carried in attestations.
  • Cannot produce cross-member atomic outcomes. Atomicity is not a primitive; a compromised module cannot force two members to jointly commit something they did not independently commit.
  • Cannot compel members. A compromised Atlas cannot force dashboards to trust it; a compromised Chronicle cannot rewrite what honest replayers and external anchors have already recorded.

What a compromised coalition can do

Conservatively:

  • Poison module commits. A majority-compromised module can publish incorrect records. Integrators reading those commits observe the misbehaviour in public and can object, migrate, or appeal to on-chain settlement.
  • Mislead Atlas consumers. A compromised Atlas can publish wrong endpoint hints, stale TDX Measurements pins, or fabricate membership. Dashboards relying on Atlas see degraded accuracy; the members themselves are unaffected.
  • DoS the module tier. A committee that loses majority stops producing new commits. Referenced members and their own pipelines are unaffected.
  • Publish a misleading CoalitionConfig. A coalition operator can publish a CoalitionConfig that references members or composite organisms the integrator did not expect. Integrators guard against this by compiling in the CoalitionConfig explicitly and auditing its contents — a misleading fingerprint is a visible artefact.
  • Stop publishing Chronicle entries. The absence of an entry is observable; a coalition that goes silent loses trust even if it cannot rewrite the past.

Compositional table

PropertyDepends on
Per-lattice block-building propertiesThat lattice’s full builder-level assumption stack
Per-organism propertiesThat organism’s own assumption stack
Composite-organism commit integrityComposite-organism committee majority-honest
Composite-organism confidentiality (if TDX)Composite-organism TDX attestation + spanned members’ upstream confidentiality
Atlas accuracyAtlas committee majority-honest + per-member operator correctness
Almanac monotonicityAlmanac committee majority-honest
Chronicle tamper-evidenceOn-chain anchor path honest OR one honest ex-member’s signed archive survives
Chronicle completenessChronicle committee majority-honest
Compute scheduling integrityCompute committee majority-honest
Compute workload attestation (TDX)Provider TDX Measurements match the grant’s expected_mrtd at workload startup
Ticket-issuer recognitionComponent’s own TicketValidator composition; coalition does not impose
Coalition observabilityAt least one honest replayer can read every component’s commit log
Accurate aggregated attributionEvery spanned upstream honest AND composite organism honest
Cross-member partial-outcome disciplineIntegrator-side risk management (no protocol support)
Coalition livenessEvery referenced member’s liveness AND every referenced composite organism’s liveness

The decomposition is the point. A coalition that misbehaves at one tier degrades the guarantee dependent on that tier; it does not collapse everything.

Operator responsibilities recap

Every operator running a committee member in any composite organism, module, or standalone organism is responsible for the same set of obligations a lattice-organism operator is (running the attested image, protecting committee-admission secrets, rotating on schedule, reporting anomalies).

Cross-member composite-organism operators add one responsibility:

  • Cross-member dependency reporting. When a referenced member’s stable id or content hash bumps, the composite-organism operator files an advisory to any coalition operators referencing the composite organism and to integrators so updates propagate with a known cadence, not silently. If any referencing coalition ships a Chronicle, that advisory lands in the next Chronicle entry.

Cross-references

Deferred-primitives pressure

audience: contributors

The blueprint defers enforceable coalition-level primitives: no protocol-level fees, no in-protocol membership requirements, no admission filters the substrate itself imposes, no adjudication machinery. Topology-intro names this the deferred-primitives space. The CLAUDE.md conventions flag any drift toward it as a bug.

This page names the site on the blueprint’s surface where that drift is most likely to arrive: the web2 compute-bridge walkthrough. Compute and Randomness both have a market-for-supply structure, which is what makes the blueprint useful for the work the book is about, and also what makes them the obvious surfaces for regulatory pressure to attach to.

Why compute sits on the edge

Compute is the basic service that touches the outside world at the closest range. Atlas, Almanac, and Chronicle are internal to the coalition — a directory, a clock beacon, an audit log. Compute is not: it bridges to cloud providers and bare-metal hosts, and those two domains already carry regulation.

Export control on AI accelerators. AI-specific workload reporting — US EO 14110, EU AI Act Article 51 and onward, the UK regulator frameworks. GPU licensure. Jurisdictional cloud-residency rules. Whatever of these applies to a compute-bridge operator at their jurisdiction of incorporation applies whether or not the substrate knows about it.

Compute also carries settlement evidence. The requester hands the module an opaque hash; off- module that hash usually resolves to an on-chain payment, which brings money-transmitter frameworks, FATF travel-rule regimes, and per-session reporting thresholds into play once values cross a declared floor.

Compute hosts third-party workloads. Cloud providers have been subpoenaed for workload records; a compute-bridge operator served with a subpoena for its ComputeLog stream cannot refuse on the grounds that shuffle anonymisation hid the requester — the log still names the provider, the window, and the usage.

Reputation organisms that commit binding scores about named providers sit adjacent to defamation law and, depending on market share, competition law. A coalition that pins a reputation floor in its member validators is running a light-touch licensure regime in all but name.

Randomness inherits the same exposure through the same market-for-supply structure. Beacon providers often operate in already-regulated domains (lottery, gambling-adjacent randomness, public-sector randomness). The quirks are different from Compute’s, the shape of the creep is the same.

What the creep looks like

Each vector below usually arrives as a small, technical improvement. Stacked, they rebuild a regulator on top of the substrate.

  • Requester due diligence. “A small allowlist on ComputeRequest to prevent abuse.” The allowlist becomes protocol-level admission; providers end up compelled to enforce it whether or not their jurisdiction requires it.
  • Export control on workload images. “The scheduler refuses images whose manifests declare restricted scientific domains.” The scheduler committee becomes a content regulator; coalitions that do not carry the filter become de facto unavailable in regulated jurisdictions.
  • Provider licensure. “Registration fee or certification attestation before a beacon provider’s card is accepted.” A certification body emerges adjacent to the scheduler; entry is gated.
  • Settlement as money-transmission. “The module verifies settlement clears a jurisdictional floor before clearing the grant.” The module is now a transaction filter; the operator is a money-transmitter by proxy.
  • Reputation defamation or antitrust. “The coalition pins a reputation floor; non-compliant providers stop receiving grants.” A de facto ban; the provider’s recourse is litigation against the coalition operator.
  • Platform liability. “The bridge retains ComputeLogs for N years under subpoena-friendly retention.” The log stream becomes a compliance artefact; the substrate is a records system.
  • Jurisdiction over the scheduler committee. “Committee members must all reside in one jurisdiction for serviceability.” Committee geography becomes a legal foothold; the voluntary-members property slips.
  • Continuity-of-service. “Retirement markers require N-day notice; early retirement triggers operator liability.” The operator’s exit guarantee (see web2 sustainability — operator exit) degrades from unconditional to gated.
  • Gambling and fair-draw frameworks. “Randomness logs every draw’s use case to satisfy audits.” The substrate acquires an audit surface; beacon consumers become auditable subjects.

Each item is implementable as a content-field change to a module’s OrganismConfig or a TicketValidator clause. The slope is gentle. The destination is recognisable only after several steps.

How creep shows up in a proposal

A proposal that drifts into the deferred-primitives space usually does not name itself that way. It will read like a local optimisation with one of a few familiar framings. A temporary safeguard. Just a small content parameter. Optional by default. For the benefit of users. Because the regulator requires it.

None of the framings is wrong on its own. A temporary safeguard can be a reasonable ACL. A content-parameter change is how modules are configured in the first place. An opt-in flag empowers operators. User protection is obviously a goal. Regulators are real.

The question is where the filter is applied. An opt-in flag on an operator’s own TicketValidator is inside the blueprint. The same filter pinned in a module’s content, propagating to every provider on the substrate, is outside it.

How to tell

Four questions to run a proposal through. Failing any one means the proposal belongs on its own branch, with its own trust composition and its own audience.

  1. Is the filter opt-in at a TicketValidator, or protocol-level in module content?
  2. Who decides admission — the coalition operator, or the substrate?
  3. Is the sanction voluntary degradation (a reputation score drops, subscribers unbond, a validator refuses new tickets) or compulsion (a module refuses to commit a properly-formed request because of who the requester is)?
  4. Does the change re-introduce a supra-agent authority — a single party whose decisions the substrate is arranged to enforce?

A proposal that passes all four is a new TicketValidator clause, a new reputation organism, or a new module content field whose semantics are observational, not exclusionary. A proposal that fails any of them is a proposal for the deferred-primitives space. The discipline is clear: it lives on its own branch, rebuilds the trust composition from first principles, and earns its way.

What the stance provides

The stance this page resists is not “regulation is illegitimate”. It is “regulation is inevitable, so bake it into the substrate”. The blueprint rejects the second claim on engineering grounds. Buterin’s d/acc: one year later (2025) makes the closest kin argument for TEEs, zkproofs, and voluntary coordination rails as alternatives to substrate-level enforcement; the Legitimacy essay (2021) is the earlier version of why substrate-level enforcement forfeits the property that makes the infrastructure useful. Buterin’s On balance-of-power as a goal for the 21st century (2025) is the corresponding positive frame: once any sector’s natural limits recede, the remaining check is structural, and substrate-level enforcement removes a check rather than adding one. The deferred-primitives space is named because that is where substrate-level enforcement would land if it landed anywhere; the book defers it explicitly so the structural check stays.

The reasons here:

  • Operator-boundary compliance composes. An operator facing a jurisdictional obligation adds a TicketValidator clause that requires whatever the obligation calls for — KYC evidence, an export-control attestation, a money-transmitter licence root. Every bonded member sees the clause, admits it or does not, and the composition stays readable.
  • Substrate-level compliance does not. A filter pinned in module content propagates to every provider and requester, regardless of whether their jurisdiction would have imposed it. The module becomes a global regulator for a local concern.
  • The operator’s exit is the substrate’s ultimate non-compulsion guarantee. A coalition operator facing unacceptable pressure retires the coalition; providers exit; requesters rebind elsewhere. Retirement markers (see sustainability) are the substrate’s answer to pressure on a named operator, not a substitute for the operator’s compliance posture.

Randomness

Randomness has the same structural exposure as Compute. Three quirks worth naming:

  • Beacon providers in gambling or lottery jurisdictions are already licensed; a provider card admitting only licensed providers is the same admission slippage as Compute’s.
  • Some jurisdictions require verifiable draws for regulated use cases (public lotteries, securities allocations). The module produces verifiable draws already; the slippage is when the module also enforces an audit-trail retention requirement.
  • Beacon challenges by design go on Chronicle, not a module-owned stream. A proposal to move them into a dedicated compliance record — signed committee verdicts retained indefinitely for regulator consumption — is the same substrate-becomes-records-system pattern as Compute’s ComputeLog retention.

The four questions above apply identically.

Cross-references

Roadmap

audience: contributors

This roadmap covers the coalition blueprint, not the v2 lists of any individual composite organism, module, or standalone organism. Each crate ships its own internal roadmap; the zipnet crate’s Roadmap to v2 is the template future crates follow.

Items below are ordered by external-impact visibility, not by engineering order; implementation order is determined by what the first production coalition requires.

v0.1 — Blueprint (this document)

Specification complete. No crates shipped. Audience: contributors who want to challenge the composition shape before composite-organism or module implementation starts.

v0.2 — Coalition meta-crate walking skeleton

Goal: one coalition meta-crate exists, its CoalitionConfig type compiles against a fixed set of example member references, and its coalition_id() derivation is stable and testable.

Minimum content:

  • Crate layout. One coalition meta-crate owning CoalitionConfig<'a>, OrganismRef<'a>, OrganismConfig<'a>, TicketIssuerConfig<'a>, the derivation helpers, the module lookup helpers (atlas(), almanac(), chronicle()), and re-exports of builder::{LatticeConfig, UNIVERSE}. No runtime yet.
  • Lifetime parameterisation. Every public struct is #[non_exhaustive] and parameterised over 'a. const instances continue to compile under 'static inference; runtime construction is first-class.
  • Schema version byte. SCHEMA_VERSION_U8 = 1 folded as the first element of every identity preimage.
  • Stable-id / content-hash split. Both LatticeConfig and OrganismRef expose a stable_id() accessor separate from their full fingerprint.
  • Derivation tests. Golden-vector tests ensuring a fixed CoalitionConfig produces a fixed fingerprint, and that each included member’s fingerprint is unchanged by coalition membership.
  • Mixed-composition tests. A coalition with zero lattices and two standalone organisms derives correctly; a coalition with two lattices and zero organisms derives correctly; mixes derive correctly.
  • Module-helper tests. Helpers return Some when a module by the well-known name is present, None otherwise.
  • Book examples. Every rust,ignore snippet in this book that references CoalitionConfig type-checks against the v0.2 meta-crate signature.

Non-goals for v0.2:

  • Any composite-organism implementation. Composite organisms arrive piecemeal once the meta-crate is stable.
  • Any module implementation. First module and the ticket issuer land in v0.3.
  • Any standalone-organism implementation. Those live in their own crates; the meta-crate only references them.
  • On-wire types. No new wire types are added at the coalition layer beyond what each organism (composite, module, or standalone) commissions for itself.

v0.3 — First module (Atlas) + ticket issuance

Goal: the first module ships end-to-end and validates the coalition’s civic-services pattern; the optional ticket-issuance root ships alongside because it is mechanically simpler than any module.

Atlas is chosen first because it has the narrowest trust shape and the shortest state machine. It exercises every part of the derivation and subscription path without introducing threshold cryptography or cross-chain auction semantics.

Minimum content:

  • coalition-atlas crate with:
    • Config fingerprint folding the coalition root and the set of member references the Atlas catalogues.
    • Atlas::<MemberCard>::read and Atlas::<MemberCard>::publish typed constructors.
    • A small state machine that commits member cards (metadata, endpoint hints, ticket-issuance roots, TDX Measurements) per member reference, co-signed by the Atlas committee. The card format handles both lattices and standalone organisms.
  • Ticket-issuance support in the coalition meta-crate: TicketIssuerConfig plumbed into CoalitionConfig with derivation under COALITION_ROOT.derive("tickets").
  • Integration test: stand up two members (mocked — one lattice, one organism), one Atlas module, optional ticket issuer, and demonstrate an integrator binding to all three through one CoalitionConfig.

v0.4 — Almanac + Chronicle

Goal: two more modules ship.

  • coalition-almanac crate with committee-driven tick commits. Per-member observed_at vector captured at commit time. Integration test: a correlator composite organism aligns events from two members to almanac ticks.
  • coalition-chronicle crate with append-only audit log. Per-member signatures on every entry; optional on-chain anchor path with configurable cadence. Integration test: coalition republishes a CoalitionConfig with a new member; Chronicle records the transition and emits an anchor commit at the next cadence boundary.

These land together because they share infrastructure (monotonic committee-signed commits) and because both are strictly additive to v0.3.

v0.5 — First commissioned composite organism + retirement markers

Goal: the first composite organism whose state machine depends on cleartext order flow from multiple lattices.

Minimum content:

  • coalition-intents crate following the intent-router pattern in composite organisms. Derives independently of any coalition; the crate ships an example OrganismConfig and example coalitions that reference it.
  • TDX admission on every committee member.
  • Integration test: intents submitted on lattice A are routed to lattice B’s offer input and a downstream tally commit reflects the cross-chain attribution.
  • Per-member stall policy documented in the crate’s composition-hooks.md.
  • Retirement marker support across all shipped crates (coalition-atlas, coalition-almanac, coalition-chronicle, coalition-intents): every committee emits a terminal RetirementMarker before shutting down; the Chronicle records it as OrganismRetired or ModuleRetired.

v0.6 — Shared attribution ledger + Compute

Goal: a second commissioned composite organism demonstrating fan-in attribution, plus the fourth module.

  • coalition-ledger crate following the shared-ledger pattern in composite organisms.
  • coalition-compute crate implementing the Compute module spec in basic services — Compute. Integration test: an agent organism submits a ComputeRequest for a TDX image, receives a ComputeGrant, the provider starts the workload with matching TDX Measurements, the provider emits a ComputeLog on completion.

(Passport is gone; ticket issuance is in v0.3.)

v1.0 — First production coalition

Goal: one coalition runs on mainnet references continuously for a month with no protocol-level incidents.

  • Rolling upgrades of composite organisms and modules. Until this point, “stop the service, bump the CoalitionConfig, restart” is an acceptable release strategy; at v1.0 it is not.
  • Snapshot + state-sync for every composite organism’s and every module’s state machine.
  • Full operator runbooks under operators/, graded by severity and audited externally.
  • Stable CoalitionConfig serialisation format. CoalitionConfig::from_hex is safe to use as the handshake after v1.0.

Longer-term items (no version assigned)

Versioning

Carrying the zipnet/builder policy into the coalition model with three adjustments.

  • Per composite organism / module: lockstep at the organism level. Commissioned composite organisms ship and version on their own schedule independent of any coalition that references them — because composite organisms no longer derive under a coalition root, a composite-organism upgrade does not force every coalition referencing it to re-derive. Coalitions simply reference the new fingerprint when they wish.
  • Per coalition: version-in-name for the coalition identity. A coalition retirement is an operator- level decision and produces a new instance name (ethereum.superchain-v2026q2). Individual modules inside a stable coalition name can still upgrade in lockstep without retiring the coalition.
  • Per member reference: stable-id pinning plus optional content-hash pinning. A CoalitionConfig references members by stable id. Composite organisms and modules choose per-component whether to also pin the content hash. Whether content-hash-pinning becomes a coalition-wide policy rather than a per-component choice is open for v0.3 decision.

Neither policy is load-bearing for v0.2 / v0.3. The first v1.0 release forces the decision.

Cross-coalition coordination

Out of scope for v0.1. A composite organism whose content folds the relevant members directly can be referenced independently by multiple coalitions; the cross- coalition commit is whatever that composite organism commits. No new primitive is needed. Research-complete, engineering-deferred.

TDX-attested modules

The v0.3 Atlas is a minimal, non-TDX module. A TDX- attested Atlas — where the committee commits cards only over attested images — is a v1+ refinement. Same for TDX-attested Almanac, Chronicle. The blueprint is unchanged; the refinement touches only the crates.

Optional cross-coalition directory

Not a core feature; same argument as the lattice directory in builder. A shared Map<CoalitionName, CoalitionCard> listing known coalitions may ship as a devops convenience. If built, it must:

  • be documented as a convenience, not a binding path;
  • be independently bindable — the coalition meta-crate never consults it;
  • not become load-bearing for ACL or attestation.

Flag in-source as // CONVENIENCE: if it lands.

Byzantine liveness for every organism committee

Mosaik’s Raft variant is crash-fault tolerant. The zipnet liveness item applies to every committee. A future BFT variant in mosaik would be inherited by every component; until then, a deliberately compromised committee member can DoS liveness in its own committee.

Composite-organism-level confidentiality beyond TDX

Some composite-organism roles (cross-chain intent routing over many chains, cross-feed correlation of sensitive oracles) may want post-quantum confidentiality ahead of their upstream members themselves. Research-complete for several threshold schemes; engineering-deferred. The organism surface does not change; only the crypto inside the composite organism’s state machine does.

New mid-rung composition classes

Builder is the first fully-specified class of mid-rung composition (block-building lattices). Other classes may follow — attestation fabrics, oracle grids, identity substrates with their own collective shape — each with its own book and its own handshake. When one does:

  • The new class’s book specifies its own FooConfig and derivation discipline, mirroring builder.
  • The coalition meta-crate may add a new referenced slice (pub fabrics: &'a [FabricConfig<'a>], etc.) or may continue referencing those compositions via their root organisms. Either works; the tradeoff is ergonomic.
  • Composite organisms gain the ability to fold the new class’s fingerprints into their Config alongside lattices and organisms.
  • Atlas MemberCard schemas are extended via #[non_exhaustive] field additions to carry metadata about the new kind.

Research-and-engineering-deferred. The coalition blueprint grows in lockstep with whichever class lands first.

Deferred-primitives space (research stance)

The blueprint explicitly refuses deferred-primitives: enforceable policies over members, taxation, judiciary, mandatory membership. The refusal is load-bearing for the current trust and composition stories.

A future proposal could make a case for one deferred primitive at a time, as a separate design with its own book branch. Any such proposal must:

  • give a full trust composition for the new primitive showing what it does to the existing guarantees;
  • specify a migration path for coalitions that ship the current opt-in shape;
  • earn its way past the objection that it reintroduces supra-member authority the current blueprint does not provide.

No concrete deferred-primitives proposal is planned. The space is flagged so contributors know where the current scope ends and where fresh proposal work would begin.

What this roadmap does not include

  • Specific crate-versioning schedules. Each crate owns its own version cadence.
  • A list of composite organisms, organism categories, or lattice classes the blueprint wants shipped. Unlike builder’s six-organism commitment, the coalition blueprint stays open beyond the five basic services. The roadmap names three plausible first commissioned composite organisms; the catalogue grows as cross- member problems force new ones.
  • Operator-onboarding contractual detail. Coalition operators run different organisations under different legal regimes; the book does not try to standardise that.
  • Adoption strategy. The book specifies and documents; adoption is the operators’ concern.

Glossary

audience: all

Domain terms as used in this book. Where a term is inherited from mosaik, zipnet, or builder, the entry points at the authoritative source rather than re- deriving.

Almanac. A basic service: a shared clock / sequence beacon members may use for cross-member timing. See basic services.

Atlas. A basic service: a directory of members with operator-supplied metadata (endpoint hints, ticket- issuance roots, TDX Measurements pins). See basic services.

Basic service. A coalition-scoped module whose shape is specified once in the blueprint so every instance means the same thing across coalitions. Five are specified: Atlas, Almanac, Chronicle, Compute, Randomness. A coalition may ship any subset (zero through all five). Compute and Randomness additionally have a market-for-supply structure where the module is a scheduler-and-registry and separate providers compete to register.

Bridge organism. The builder book’s name for a speculative cross-lattice organism. In this blueprint, generalised to a composite organism — an organism whose Config fingerprint folds two or more member references. See composite organisms.

Chronicle. A basic service: a tamper-evident audit log of coalition actions (publications, rotations, retirements). See basic services.

Compute. A basic service: a scheduler and registry through which coalition members submit ComputeRequests for workloads identified by image pre-hash (crate source + min CPU / RAM / TDX) and receive ComputeGrants matching them to registered providers. The module commits the match; the actual compute runs on a separate provider. See basic services.

Randomness. A basic service: a scheduler committing Stream<BeaconTick> of unbiasable beacon values plus a Collection<ProviderId, ProviderCard> of registered providers. The module commits the rounds; the actual randomness is produced by separate providers (threshold-BLS committees, dVRFs, drand-alike external beacons, TDX-attested per-round derivations). Consumers derive targeted draws locally by hashing the beacon value with a domain tag. The coalition’s admitted scheme families determine the unbiasability argument consumers inherit. See basic services.

Member. A lattice or organism referenced by a coalition’s CoalitionConfig. “Referenced unit of the coalition”.

MemberId. The 20-byte prefix of a member’s blake3 stable-id fingerprint, used as a compact key in cross- member commits. The full 32-byte fingerprint lives in Atlas entries and in evidence pointers. See composition — Two keys.

Coalition. A fingerprint-addressed composition of zero or more lattices and zero or more organisms (standalone or composite), possibly shipping up to five coalition-scoped modules (Atlas, Almanac, Chronicle, Compute, Randomness) and an optional ticket-issuance root. Identified by a CoalitionConfig. Operator-scoped, not a consensus unit, not an ACL root. An opt-in composition offering services to its members. See topology-intro.

CoalitionConfig. The parent struct a coalition operator publishes and an integrator compiles in. Contains the coalition’s name, the ordered LatticeConfigs it references, the ordered OrganismRefs it references (including any composite organisms), and an optional TicketIssuerConfig. See topology-intro — Coalition identity.

COALITION_ROOT. The derived fingerprint used as the root for each coalition-scoped module’s (Atlas, Almanac, Chronicle, Compute, optional ticket issuer) identity derivation. Commissioned composite organisms derive independently and do NOT fold COALITION_ROOT. See topology-intro — Membership-by-reference.

Composite organism. An organism whose Config fingerprint folds two or more member references (lattices, OrganismRefs, or a mix) and whose public surface coordinates across the referenced members. Its identity is independent of any coalition: one composite organism may be referenced by many coalitions. See composite organisms.

OrganismConfig. The parent struct for a composite organism’s Config. Folds the organism’s role name, ordered spanned lattices, ordered spanned standalone organisms, content parameters, and ACL. Does not fold a coalition root. See composite organisms — the Config fingerprint.

Content + intent addressing. The discipline every consensus-critical id in every organism, lattice, or coalition obeys: id = blake3(intent ‖ content ‖ acl). Inherited verbatim from zipnet and builder.

Content hash. The portion of a member’s fingerprint that folds its ACL, TDX Measurements, and state-affecting parameters. Bumps on operational rotations; distinct from the stable id. See topology-intro — Member reference shape.

Costly signalling. A mechanism-design pattern in which a signal’s cost is lower for legitimate senders than for impostors, so the separating equilibrium distinguishes the two (Spence, Job Market Signalling, 1973). In this book, attestation fabrics are the costly-signalling rendering: the cost is a TDX quote, an ML-inference receipt, or a hardware-bound attestation. See emergent coordination — attestation fabrics.

Deployment. A single running instance of an organism, lattice, or coalition. Identified by the relevant Config fingerprint.

Evidence pointer. A reference from a composite organism’s commit back to the member commit it depends on. Resolved on replay to validate the organism’s state-machine transition.

Fan-in organism. A composite organism aggregating facts from multiple origin members (e.g. a shared-ledger organism, a cross-feed correlator).

Fan-out organism. A composite organism distributing a fact to multiple target members (e.g. an intent router).

Fingerprint. A synonym for the content + intent addressed id of a Config (coalition, lattice, or organism). Mismatched fingerprints are the ladder’s debuggable failure mode at every rung.

Fixed shapes, open catalogs. The blueprint discipline of specifying shapes (CoalitionConfig, OrganismConfig, the five basic services, the ticket-issuance shape) once and leaving the catalogs (which composite organisms, which organism categories, which lattice classes, whether a coalition ships any modules) open. See introduction — Fixed shapes, open catalogs.

Deferred-primitives space. The speculative (and deferred) class of coalition-level primitives — enforceable policies over members, taxation, judiciary. Explicitly out of scope; see introduction — Fixed shapes, open catalogs.

Hypergame. A generalisation of non-cooperative game theory in which players hold different beliefs about the game being played (Bennett, 1977; see the 2025 survey). Cited in this book only to name the failure of common-knowledge-of-rationality for LLM agents; the book does not model agent behaviour as a hypergame, it just notes that classical equilibrium analyses of LLM populations do not compose.

Integrator. External developer consuming a coalition, member, or composite organism. Never client (ambiguous; the book uses PeerId for the peer-side identity).

Intent-router pattern. A composite organism that reads cleartext from spanned lattices’ unseal::UnsealedPools and commits a routed-intents collection per target lattice. See composite organisms — intent-router pattern.

Kreps–Milgrom reputation. A repeated-game mechanism (Kreps, Milgrom, Roberts, Wilson, Rational Cooperation in the Finitely Repeated Prisoner’s Dilemma, 1982) under which a long-lived observer commits a summary of a player’s history and downstream players use the summary to gate future interaction. The book’s reputation feedback pattern is a committee-committed rendering with consumer-side opt-in — consumers choose whether to consult the reputation organism’s scores.

Lattice. One fully-specified mid-rung composition of organisms. Builder specifies the first class of lattice: one end-to-end block-building deployment for one EVM chain, identified by a LatticeConfig fingerprint. Nothing in this blueprint assumes a lattice is a block-building lattice; other classes may follow their own proposals. Coalitions reference lattices; they do not own them.

LatticeConfig. Builder’s parent struct for a block- building lattice. Unchanged in this blueprint. See builder glossary.

Mechanism design. The subfield of game theory concerned with designing the rules of a game so that self-interested participants produce a desired outcome. In this book, mechanism design enters wherever the operator picks a clearing rule, a scoring function, or a verification rule — the coordination-market, reputation-feedback, and attestation-fabric patterns all admit a mechanism-design reading. The book treats mechanism design as a lens on the operator’s chosen rules, not as a prediction of how agents will behave. See societies — Game theory as a lens, not a prediction.

Module. A coalition-scoped component whose identity derives under COALITION_ROOT.derive("module").derive(name). The five basic services (Atlas, Almanac, Chronicle, Compute, Randomness) are modules. Commissioned composite organisms are NOT modules — they derive independently.

TDX Measurements. Intel TDX measurement register binding a boot image to the hardware root of trust. Pinned per TDX-gated organism in that component’s Config. See mosaik — Intel TDX.

Narrow public surface. The discipline of exposing one or two primitives per organism on the shared universe. Inherited from the zipnet design intro.

No-regret learning. An online-learning regime in which a player’s time-averaged payoff approaches the best fixed action’s payoff in hindsight. Classical game- theoretic convergence results assume no-regret play; Park et al. (2024) show that LLM-class agents are not no-regret in canonical repeated games. Cited in this book to flag that equilibrium analyses of LLM populations do not compose in the way the classical literature assumes.

Operator. Team running a lattice, standalone organism, composite organism, module, or coalition (or any combination). See introduction.

Organism. A mosaik-native service with a narrow public surface. The six builder organisms (zipnet, unseal, offer, atelier, relay, tally) inside each block- building lattice, every composite organism, every module, and every standalone organism a coalition references are organisms.

OrganismRef. The coalition’s reference type for an organism: a role name plus the organism’s stable id and optional content hash. The concrete Config type lives in the organism’s own crate and is opaque to the coalition meta-crate. See topology-intro — Coalition identity.

PeerId. The mosaik-native peer identity used by every node on the universe. Peers may rotate their PeerId per submission (the shuffle’s anonymity property — a fresh PeerId per sealed submission) or hold a stable PeerId bonded into an organism’s TicketValidator ACL (the ordinary integrator case). This book does not define a coalition-scoped peer identity distinct from PeerId; the rotating and stable cases are usage patterns of the one type. See mosaik — Identity & Networking and mosaik — Bonds & Peer Connections.

Retirement marker. A record a composite organism, module, or coalition commits to its own stream before its committee shuts down, declaring effective retirement time and an optional replacement pointer. See basic services — Retirement markers.

Separating equilibrium. In a costly-signalling game, the equilibrium in which senders of different types choose distinguishable signals because the cost of the signal is type-dependent. The book’s attestation fabrics rely on a separating structure: legitimate participants produce TDX or inference-receipt signals cheaply; impostors cannot.

Shared-ledger pattern. A composite organism that aggregates per-lattice tally::Refunds into a cross-origin-member attribution feed. See composite organisms — shared-ledger pattern.

Shuffle. Abstract primitive that takes N sealed submissions from distinct senders and makes their cleartext available to downstream readers in a way that breaks the sender → submission link. Concrete shuffle constructions include threshold-decryption committees (as in zipnet), cMix-style mix networks, threshold-BLS decryption pools, and FHE- backed release. Every example in this book that mentions anonymous submission composes on top of a shuffle; zipnet is the specific implementation the upstream project ships and the one against which the book’s worked examples bond. See introduction — Shuffle.

Shared policy. The mechanism by which mosaik AI agents self-organize and converge: each agent’s TicketValidator admits the same fingerprint — either the Config.content of a mediating organism (reputation’s utility function, a market’s clearing rule, an attestation fabric’s verification rule, a stigmergic collection’s write-side contract) or, for TDX deployments, a shared set of TDX Measurements that binds the runtime policy itself. Every emergent-coordination pattern in the book is an instance of this mechanism; every bond remains voluntary on both sides. See ai/emergent-coordination.md and, for the TDX arm, ai/sustainability.md.

Stable id. The (instance_name, network_id) blake3 hash a member publishes as its durable identifier. Changes only on retirement, not on operational rotations. See topology-intro — Member reference shape.

Standalone organism. An organism living directly on the universe rather than inside a lattice. Oracles, attestation fabrics, identity substrates, data- availability shards, analytics pipelines, and the like — all referenced by a coalition via OrganismRef.

StateMachine. Mosaik’s term for the deterministic command processor inside a Group<M>. Every organism has its own state machine. See mosaik groups.

Stall policy. Per-composite-organism rule for behaviour when one spanned member is not producing inputs for the current clock event. Either commit with partial evidence (preserving liveness) or stall the event (preserving quality). Documented per composite organism.

TDX. Intel Trust Domain Extensions. The TEE technology mosaik ships first-class support for. Used by composite organisms and sensitive standalone organisms. See mosaik TDX.

TicketIssuer. An optional coalition-scoped mosaik ticket issuer. Non-authoritative: no component is required to accept tickets from this issuer; components opt in by including the issuance root in their own TicketValidator composition. See ticket issuance.

Universe. The shared mosaik NetworkId (builder::UNIVERSE = unique_id!("mosaik.universe")) hosting every coalition, every lattice, and every organism. See mosaik — Identity & Networking.

VCG (Vickrey–Clarke–Groves). A family of truthful auction mechanisms (Vickrey 1961; Clarke 1971; Groves 1973) in which each bidder’s dominant strategy is to bid their true valuation. Cited in this book as one clearing-rule option for coordination markets; the book specifies the market surface but does not mandate a clearing rule. The operator picks.