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:
- The
ProviderCardcollection — every provider in the coalition, the bridge included. This is how the bridge sees its competitors’ declared rates, TDX posture, and region coverage. - Subscriber cardinality — the count of coalition agents bonded to this bridge’s own card. Rises and falls with the bridge’s competitiveness.
- 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.