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 an ordered element after
confluences.
How components opt in
A confluence, module, or any organism 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(confluence_mrtd));
No component is required to. A confluence 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_ROOTare 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 confluences whose committees cross-bond frequently benefits from a single issuance root rather than N per-confluence 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.