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

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