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

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