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-zeroUniqueId, 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::latticesis&[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’sconstblocks 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::LatticeConfig →
builder::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(withcontent_hashpinned),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 type | Coalition primitive it maps to |
|---|---|
ConsentModel | TicketValidator composition at the admission boundary |
ConsentEvidence | What a bond’s self-quote, ticket, or stream commit records |
DecisionRule | A basic-service module’s quorum or a composite organism’s committee threshold |
Delegation | A shared ticket issuer, a committee’s publication authority, a peer-Compute grant |
Revocability | Which retirement markers the delegation supports |
Legitimacy | What the consumer’s TicketValidator composition actually checks |
FranchiseScope | The admission criterion at the component’s TicketValidator |
CompositionForm | Whether a coalition is multi-operator, nested, or direct |
SovereigntyClaim | A 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
crates/coalition/source- Part III — contributors — topology intro — the design chapter specifying every shape this crate implements.
- Part III — contributors — composite organisms
— the
OrganismConfigshape in full. - Part III — contributors — basic services — the five basic-service shapes.
- Part III — contributors — ticket issuance
— the
TicketIssuerConfigshape.