use std::collections::HashMap;
use std::time::{Duration, Instant};
use super::continuity::{
AttestedStatus, Continuity, DeliveredBeat, DisruptReason, ObservationCell, ProjectedReadiness,
};
use super::identity::{
AudienceScopeCommitment, CapabilityInterestKey, Digest256, ProviderInterestKey,
ProviderObservationKey,
};
use super::incarnation::{Incarnation, IncarnationSeqGate};
use super::table::{DownstreamId, InterestTable, RegisterOutcome};
#[derive(Clone, Debug)]
pub struct Attestation {
pub key: ProviderObservationKey,
pub origin_incarnation: Incarnation,
pub status: AttestedStatus,
pub estimated_start: Option<Duration>,
pub seq: u64,
pub promised_cadence: Duration,
pub fingerprint: Digest256,
}
impl Attestation {
pub fn new(
key: ProviderObservationKey,
origin_incarnation: Incarnation,
status: AttestedStatus,
estimated_start: Option<Duration>,
seq: u64,
promised_cadence: Duration,
) -> Self {
let mut hasher = blake3::Hasher::new_derive_key("net.sensing.attestation.fingerprint.v1");
hasher.update(&key.provider.to_le_bytes());
hasher.update(&key.capability_generation.to_le_bytes());
hasher.update(&origin_incarnation.get().to_le_bytes());
hasher.update(key.interest.interest_digest.as_bytes());
hasher.update(&[match status {
AttestedStatus::Ready => 0u8,
AttestedStatus::NotReady => 1,
AttestedStatus::ProviderUnknown => 2,
}]);
hasher.update(
&estimated_start
.map(|d| d.as_nanos())
.unwrap_or(u128::MAX)
.to_le_bytes(),
);
hasher.update(&seq.to_le_bytes());
hasher.update(&promised_cadence.as_nanos().to_le_bytes());
let fingerprint = Digest256::from_bytes(*hasher.finalize().as_bytes());
Self {
key,
origin_incarnation,
status,
estimated_start,
seq,
promised_cadence,
fingerprint,
}
}
pub fn branch(&self) -> ProviderInterestKey {
ProviderInterestKey::new(self.key.interest.clone(), self.key.provider)
}
fn as_beat(&self, continuity_bearing: bool) -> DeliveredBeat {
DeliveredBeat {
attested_status: self.status,
estimated_start: self.estimated_start,
source_incarnation: self.origin_incarnation,
capability_generation: self.key.capability_generation,
seq: self.seq,
promised_cadence: self.promised_cadence,
continuity_bearing,
}
}
}
#[derive(Clone, Debug)]
pub struct Delivery {
pub to: DownstreamId,
pub attestation: Attestation,
pub continuity_bearing: bool,
}
struct RelayKeyState {
upstream: ObservationCell,
cached: Option<Attestation>,
}
#[derive(Clone, Copy)]
struct DeliverySlot {
last_status: Option<AttestedStatus>,
last_delivered: Option<(Incarnation, u64)>,
next_due: Instant,
pending: bool,
}
pub struct SensingRelay {
factor: u32,
gate: IncarnationSeqGate,
pub table: InterestTable,
keys: HashMap<ProviderInterestKey, RelayKeyState>,
slots: HashMap<(ProviderInterestKey, DownstreamId), DeliverySlot>,
}
impl SensingRelay {
pub fn new(factor: u32, max_interests_per_peer: usize) -> Self {
Self {
factor,
gate: IncarnationSeqGate::new(),
table: InterestTable::new(max_interests_per_peer),
keys: HashMap::new(),
slots: HashMap::new(),
}
}
pub fn register_downstream(
&mut self,
key: &ProviderInterestKey,
downstream: DownstreamId,
requested_sample_interval: Duration,
soft_state_ttl: Duration,
owner_root: AudienceScopeCommitment,
now: Instant,
) -> (RegisterOutcome, Option<Delivery>) {
let outcome = self.table.register(
key,
downstream,
requested_sample_interval,
soft_state_ttl,
owner_root,
now,
);
if !matches!(outcome, RegisterOutcome::Registered(_)) {
return (outcome, None);
}
let aggregate = self.table.aggregate(key, now);
let factor = self.factor;
let state = self
.keys
.entry(key.clone())
.or_insert_with(|| RelayKeyState {
upstream: ObservationCell::register(now, requested_sample_interval, factor),
cached: None,
});
if let Some(interval) = aggregate {
state.upstream.update_interval(interval);
}
let is_new_row = !self.slots.contains_key(&(key.clone(), downstream));
let slot = self
.slots
.entry((key.clone(), downstream))
.or_insert(DeliverySlot {
last_status: None,
last_delivered: None,
next_due: now,
pending: false,
});
let warm_start = if is_new_row {
state.cached.as_ref().map(|cached| {
slot.last_status = Some(cached.status);
slot.last_delivered = Some((cached.origin_incarnation, cached.seq));
slot.next_due = now + requested_sample_interval;
slot.pending = false;
Delivery {
to: downstream,
attestation: cached.clone(),
continuity_bearing: false,
}
})
} else {
None
};
(outcome, warm_start)
}
pub fn on_attestation(
&mut self,
now: Instant,
attestation: &Attestation,
upstream_bearing: bool,
) -> Vec<Delivery> {
let branch = attestation.branch();
let Some(state) = self.keys.get_mut(&branch) else {
return Vec::new();
};
if !self
.gate
.admit(
attestation.key.provider,
attestation.key.interest.interest_digest,
attestation.origin_incarnation,
attestation.seq,
attestation.fingerprint,
)
.is_admitted()
{
return Vec::new();
}
state
.upstream
.on_admitted_beat(now, attestation.as_beat(upstream_bearing));
self.table
.set_upstream_continuity(&branch, state.upstream.continuity());
state.cached = Some(attestation.clone());
let bearing = state.upstream.continuity() == Continuity::Established;
let mut deliveries = Vec::new();
for downstream in self.table.downstreams(&branch, now) {
let Some(row) = self.table.downstream_entry(&branch, downstream) else {
continue;
};
let interval = row.requested_sample_interval;
let Some(slot) = self.slots.get_mut(&(branch.clone(), downstream)) else {
continue;
};
let edge = slot.last_status != Some(attestation.status);
let due = now >= slot.next_due;
if edge || due {
slot.last_status = Some(attestation.status);
slot.last_delivered = Some((attestation.origin_incarnation, attestation.seq));
slot.next_due = now + interval;
slot.pending = false;
deliveries.push(Delivery {
to: downstream,
attestation: attestation.clone(),
continuity_bearing: bearing,
});
} else {
slot.pending = true;
}
}
deliveries
}
pub fn poll(&mut self, now: Instant) -> Vec<Delivery> {
let mut deliveries = Vec::new();
for (key, state) in self.keys.iter_mut() {
state.upstream.expire_if_due(now);
self.table
.set_upstream_continuity(key, state.upstream.continuity());
let Some(cached) = &state.cached else {
continue;
};
let bearing = state.upstream.continuity() == Continuity::Established;
for downstream in self.table.downstreams(key, now) {
let Some(row) = self.table.downstream_entry(key, downstream) else {
continue;
};
let interval = row.requested_sample_interval;
let Some(slot) = self.slots.get_mut(&(key.clone(), downstream)) else {
continue;
};
let newer = slot
.last_delivered
.is_none_or(|prev| (cached.origin_incarnation, cached.seq) > prev);
if slot.pending && newer && now >= slot.next_due {
slot.last_status = Some(cached.status);
slot.last_delivered = Some((cached.origin_incarnation, cached.seq));
slot.next_due = now + interval;
slot.pending = false;
deliveries.push(Delivery {
to: downstream,
attestation: cached.clone(),
continuity_bearing: bearing,
});
}
}
}
deliveries
}
pub fn upstream_continuity(&self, key: &ProviderInterestKey) -> Option<Continuity> {
self.keys.get(key).map(|state| state.upstream.continuity())
}
pub fn reclaim_branch(&mut self, key: &ProviderInterestKey) {
self.keys.remove(key);
self.slots.retain(|(branch, _), _| branch != key);
}
pub fn update_branch_interval(&mut self, key: &ProviderInterestKey, interval: Duration) {
if let Some(state) = self.keys.get_mut(key) {
state.upstream.update_interval(interval);
}
}
pub fn disrupt_provider(&mut self, provider: u64, reason: DisruptReason) {
for (key, state) in self.keys.iter_mut() {
if key.provider == provider && state.upstream.continuity() != Continuity::Expired {
state.upstream.disrupt(reason);
self.table.set_upstream_continuity(key, Continuity::Expired);
}
}
}
pub fn gc_dead_slots(&mut self, now: Instant) {
let table = &self.table;
self.slots.retain(|(branch, downstream), _| {
table
.downstream_entry(branch, *downstream)
.is_some_and(|row| row.expires_at > now)
});
}
pub fn is_drained(&self) -> bool {
self.table.is_empty() && self.keys.is_empty() && self.slots.is_empty()
}
pub fn retained_branches(&self) -> usize {
self.keys.len()
}
pub fn branch_providers(&self) -> Vec<u64> {
self.keys.keys().map(|key| key.provider).collect()
}
pub fn retained_slots(&self) -> usize {
self.slots.len()
}
}
pub struct SensingConsumer {
factor: u32,
gate: IncarnationSeqGate,
cells: HashMap<ProviderInterestKey, ObservationCell>,
}
impl SensingConsumer {
pub fn new(factor: u32) -> Self {
Self {
factor,
gate: IncarnationSeqGate::new(),
cells: HashMap::new(),
}
}
pub fn register_interest(
&mut self,
key: &ProviderInterestKey,
own_interval: Duration,
now: Instant,
) {
self.cells.insert(
key.clone(),
ObservationCell::register(now, own_interval, self.factor),
);
}
pub fn on_delivery(&mut self, now: Instant, delivery: &Delivery) {
let attestation = &delivery.attestation;
let Some(cell) = self.cells.get_mut(&attestation.branch()) else {
return;
};
if !self
.gate
.admit(
attestation.key.provider,
attestation.key.interest.interest_digest,
attestation.origin_incarnation,
attestation.seq,
attestation.fingerprint,
)
.is_admitted()
{
return;
}
cell.on_admitted_beat(now, attestation.as_beat(delivery.continuity_bearing));
}
pub fn poll(&mut self, now: Instant) {
for cell in self.cells.values_mut() {
cell.expire_if_due(now);
}
}
pub fn projected(&self, key: &ProviderInterestKey) -> ProjectedReadiness {
self.cells
.get(key)
.map(ObservationCell::projected)
.unwrap_or(ProjectedReadiness::Unknown)
}
pub fn branch_projections(
&self,
interest: &CapabilityInterestKey,
) -> Vec<(u64, ProjectedReadiness, Option<Duration>)> {
self.cells
.iter()
.filter(|(key, _)| &key.interest == interest)
.map(|(key, cell)| {
(
key.provider,
cell.projected(),
cell.observation().and_then(|obs| obs.estimated_start),
)
})
.collect()
}
pub fn cell(&self, key: &ProviderInterestKey) -> Option<&ObservationCell> {
self.cells.get(key)
}
}
#[cfg(test)]
mod tests {
use super::super::identity::{
CanonicalConstraints, CapabilityId, DisclosureClass, InterestSpec, ProviderSelector,
ResultMode, WorkLatencyEnvelope,
};
use super::*;
const K: u32 = 3;
const ORIGIN: u64 = 0xE0;
const GEN: u64 = 4;
const TTL: Duration = Duration::from_secs(30);
const CADENCE: Duration = Duration::from_millis(100);
fn ms(v: u64) -> Duration {
Duration::from_millis(v)
}
fn root() -> AudienceScopeCommitment {
AudienceScopeCommitment::from_bytes([0xAA; 32])
}
fn key_for(fps: &str) -> ProviderInterestKey {
let spec = InterestSpec {
capability_id: CapabilityId::new("video.transcode"),
constraints: CanonicalConstraints::from_entries([("fps", fps)]).unwrap(),
work_latency: WorkLatencyEnvelope::start_within(ms(200)),
providers: ProviderSelector::AnyAuthorized,
result_mode: ResultMode::Any,
disclosure_class: DisclosureClass::Owner,
audience: root(),
};
ProviderInterestKey::new(spec.key(), ORIGIN)
}
struct TestOrigin {
incarnation: Incarnation,
seq: u64,
}
impl TestOrigin {
fn new(incarnation: u64) -> Self {
Self {
incarnation: Incarnation::new(incarnation),
seq: 0,
}
}
fn emit(&mut self, key: &ProviderInterestKey, status: AttestedStatus) -> Attestation {
self.seq += 1;
Attestation::new(
ProviderObservationKey::new(key.interest.clone(), key.provider, GEN),
self.incarnation,
status,
None,
self.seq,
CADENCE,
)
}
}
fn feed(consumer: &mut SensingConsumer, who: DownstreamId, now: Instant, out: &[Delivery]) {
for delivery in out.iter().filter(|d| d.to == who) {
consumer.on_delivery(now, delivery);
}
}
#[test]
fn an_attestation_only_ever_touches_its_own_provider_branch() {
let t0 = Instant::now();
let interest = key_for("30").interest;
let branch_p = ProviderInterestKey::new(interest.clone(), 0xAA);
let branch_x = ProviderInterestKey::new(interest, 0xBB);
let a = DownstreamId::Peer(1);
let mut relay = SensingRelay::new(K, 512);
relay.register_downstream(&branch_p, a, ms(100), TTL, root(), t0);
assert_eq!(
relay.upstream_continuity(&branch_p),
Some(Continuity::Unestablished),
);
let mut origin_x = TestOrigin::new(1);
let out = relay.on_attestation(
t0 + CADENCE,
&origin_x.emit(&branch_x, AttestedStatus::Ready),
true,
);
assert!(
out.is_empty(),
"an attestation for an unregistered provider branch delivers nothing",
);
assert_eq!(
relay.upstream_continuity(&branch_p),
Some(Continuity::Unestablished),
"provider P's branch is untouched — X's stream cannot establish it",
);
assert_eq!(
relay.upstream_continuity(&branch_x),
None,
"no branch state is fabricated for an unregistered provider",
);
}
#[test]
fn two_interests_on_one_capability_stay_independent() {
let t0 = Instant::now();
let k30 = key_for("30");
let k60 = key_for("60");
let a = DownstreamId::Peer(1);
let mut origin = TestOrigin::new(1);
let mut relay = SensingRelay::new(K, 512);
let mut consumer = SensingConsumer::new(K);
for key in [&k30, &k60] {
consumer.register_interest(key, ms(100), t0);
relay.register_downstream(key, a, ms(100), TTL, root(), t0);
}
for tick in 1..=3u64 {
let now = t0 + CADENCE * u32::try_from(tick).unwrap();
let out30 = relay.on_attestation(now, &origin.emit(&k30, AttestedStatus::Ready), true);
let out60 =
relay.on_attestation(now, &origin.emit(&k60, AttestedStatus::NotReady), true);
feed(&mut consumer, a, now, &out30);
feed(&mut consumer, a, now, &out60);
}
assert_eq!(consumer.projected(&k30), ProjectedReadiness::Ready);
assert_eq!(consumer.projected(&k60), ProjectedReadiness::NotReady);
for tick in 4..=20u64 {
let now = t0 + CADENCE * u32::try_from(tick).unwrap();
let out = relay.on_attestation(now, &origin.emit(&k30, AttestedStatus::Ready), true);
feed(&mut consumer, a, now, &out);
consumer.poll(now);
}
assert_eq!(consumer.projected(&k30), ProjectedReadiness::Ready);
assert_eq!(consumer.projected(&k60), ProjectedReadiness::Unknown);
}
#[test]
fn origin_restart_behind_relay_rejects_delayed_old_incarnation() {
let t0 = Instant::now();
let key = key_for("30");
let a = DownstreamId::Peer(1);
let mut relay = SensingRelay::new(K, 512);
let mut consumer = SensingConsumer::new(K);
consumer.register_interest(&key, ms(100), t0);
relay.register_downstream(&key, a, ms(100), TTL, root(), t0);
let mut old = TestOrigin::new(7);
let t1 = t0 + ms(100);
let out = relay.on_attestation(t1, &old.emit(&key, AttestedStatus::Ready), true);
feed(&mut consumer, a, t1, &out);
assert_eq!(consumer.projected(&key), ProjectedReadiness::Ready);
let mut new = TestOrigin::new(8);
let t2 = t1 + ms(100);
let out = relay.on_attestation(t2, &new.emit(&key, AttestedStatus::Ready), true);
assert_eq!(out.len(), 1);
feed(&mut consumer, a, t2, &out);
assert_eq!(
consumer
.cell(&key)
.unwrap()
.observation()
.unwrap()
.source_incarnation,
Incarnation::new(8),
);
old.seq = 100;
let t3 = t2 + ms(100);
let out = relay.on_attestation(t3, &old.emit(&key, AttestedStatus::Ready), false);
assert!(out.is_empty(), "stale incarnation must not be forwarded");
assert_eq!(
consumer
.cell(&key)
.unwrap()
.observation()
.unwrap()
.source_incarnation,
Incarnation::new(8),
);
assert_eq!(consumer.projected(&key), ProjectedReadiness::Ready);
}
#[test]
fn down_sampling_edges_and_provisional_warm_start() {
let t0 = Instant::now();
let key = key_for("30");
let (a, b) = (DownstreamId::Peer(1), DownstreamId::Peer(2));
let mut origin = TestOrigin::new(1);
let mut relay = SensingRelay::new(K, 512);
let mut watcher_a = SensingConsumer::new(K);
let mut watcher_b = SensingConsumer::new(K);
watcher_a.register_interest(&key, ms(100), t0);
watcher_b.register_interest(&key, ms(500), t0);
relay.register_downstream(&key, a, ms(100), TTL, root(), t0);
relay.register_downstream(&key, b, ms(500), TTL, root(), t0);
let (mut count_a, mut count_b) = (0usize, 0usize);
for tick in 1..=10u64 {
let now = t0 + CADENCE * u32::try_from(tick).unwrap();
let out = relay.on_attestation(now, &origin.emit(&key, AttestedStatus::Ready), true);
count_a += out.iter().filter(|d| d.to == a).count();
count_b += out.iter().filter(|d| d.to == b).count();
feed(&mut watcher_a, a, now, &out);
feed(&mut watcher_b, b, now, &out);
watcher_a.poll(now);
watcher_b.poll(now);
assert_eq!(
watcher_b.projected(&key),
ProjectedReadiness::Ready,
"loose watcher false-Unknowned at tick {tick}",
);
}
assert_eq!(count_a, 10, "strict watcher sees the full cadence");
assert_eq!(
count_b, 2,
"loose watcher is delivered at its own D, not the origin cadence",
);
let t_edge = t0 + CADENCE * 10 + ms(50);
let out = relay.on_attestation(t_edge, &origin.emit(&key, AttestedStatus::NotReady), true);
assert_eq!(
out.iter().filter(|d| d.to == b).count(),
1,
"a status edge is never held by the down-sampler",
);
feed(&mut watcher_a, a, t_edge, &out);
feed(&mut watcher_b, b, t_edge, &out);
assert_eq!(watcher_a.projected(&key), ProjectedReadiness::NotReady);
assert_eq!(watcher_b.projected(&key), ProjectedReadiness::NotReady);
let t_join = t_edge + ms(10);
let mut joiner = SensingConsumer::new(K);
joiner.register_interest(&key, ms(100), t_join);
let (_, warm) =
relay.register_downstream(&key, DownstreamId::Peer(3), ms(100), TTL, root(), t_join);
let warm = warm.expect("cache must warm-start a late joiner");
assert!(
!warm.continuity_bearing,
"warm-starts are always provisional"
);
joiner.on_delivery(t_join, &warm);
assert_eq!(joiner.projected(&key), ProjectedReadiness::NotReady);
let t_flip = t_join + ms(40);
let out = relay.on_attestation(t_flip, &origin.emit(&key, AttestedStatus::Ready), true);
assert!(!out.is_empty());
let t_join2 = t_flip + ms(10);
let mut joiner2 = SensingConsumer::new(K);
joiner2.register_interest(&key, ms(100), t_join2);
let (_, warm) =
relay.register_downstream(&key, DownstreamId::Peer(4), ms(100), TTL, root(), t_join2);
let warm = warm.expect("cache must warm-start the second joiner");
assert!(!warm.continuity_bearing);
joiner2.on_delivery(t_join2, &warm);
assert_eq!(
joiner2.projected(&key),
ProjectedReadiness::Unknown,
"cached Ready must not project Ready through a warm-start",
);
let t_live = t_join2 + ms(100);
let out = relay.on_attestation(t_live, &origin.emit(&key, AttestedStatus::Ready), true);
feed(&mut joiner2, DownstreamId::Peer(4), t_live, &out);
assert_eq!(joiner2.projected(&key), ProjectedReadiness::Ready);
}
#[test]
fn refresh_never_resets_a_live_delivery_schedule() {
let t0 = Instant::now();
let key = key_for("30");
let a = DownstreamId::Peer(1);
let mut origin = TestOrigin::new(1);
let mut relay = SensingRelay::new(K, 512);
relay.register_downstream(&key, a, ms(500), TTL, root(), t0);
let t1 = t0 + ms(100);
let out = relay.on_attestation(t1, &origin.emit(&key, AttestedStatus::Ready), true);
assert_eq!(out.iter().filter(|d| d.to == a).count(), 1);
let t2 = t1 + ms(100);
let out = relay.on_attestation(t2, &origin.emit(&key, AttestedStatus::Ready), true);
assert!(out.is_empty(), "inside D: the beat waits for the schedule");
let t3 = t2 + ms(100);
let (outcome, warm) = relay.register_downstream(&key, a, ms(500), TTL, root(), t3);
assert!(matches!(outcome, RegisterOutcome::Registered(_)));
assert!(warm.is_none(), "a refresh must not re-send the cache");
let t4 = t1 + ms(500);
let out = relay.poll(t4);
let flushed: Vec<&Delivery> = out.iter().filter(|d| d.to == a).collect();
assert_eq!(
flushed.len(),
1,
"pending live work flushes on the un-reset schedule",
);
assert_eq!(flushed[0].attestation.seq, 2);
}
#[test]
fn registration_tightens_the_continuity_window_without_a_beat() {
let t0 = Instant::now();
let key = key_for("30");
let (a, b) = (DownstreamId::Peer(1), DownstreamId::Peer(2));
let mut origin = TestOrigin::new(1);
let mut relay = SensingRelay::new(K, 512);
relay.register_downstream(&key, a, ms(200), TTL, root(), t0);
let t1 = t0 + ms(100);
relay.on_attestation(t1, &origin.emit(&key, AttestedStatus::Ready), true);
assert_eq!(
relay.upstream_continuity(&key),
Some(Continuity::Established)
);
let t2 = t1 + ms(100);
relay.register_downstream(&key, b, ms(100), TTL, root(), t2);
relay.poll(t1 + ms(400));
assert_eq!(
relay.upstream_continuity(&key),
Some(Continuity::Expired),
"a tightened aggregate must move the deadline inward immediately",
);
}
#[test]
fn multi_hop_cache_chain_cannot_launder_continuity() {
let t0 = Instant::now();
let key = key_for("30");
let mut origin = TestOrigin::new(1);
origin.seq = 99;
let mut relay_c = SensingRelay::new(K, 512);
let mut relay_b = SensingRelay::new(K, 512);
relay_c.register_downstream(&key, DownstreamId::Local, ms(100), TTL, root(), t0);
relay_c.register_downstream(&key, DownstreamId::Peer(0xB), ms(100), ms(500), root(), t0);
relay_b.register_downstream(&key, DownstreamId::Local, ms(100), TTL, root(), t0);
let t1 = t0 + ms(100);
let att100 = origin.emit(&key, AttestedStatus::Ready);
let out_c = relay_c.on_attestation(t1, &att100, true);
let to_b = out_c
.iter()
.find(|d| d.to == DownstreamId::Peer(0xB))
.expect("C forwards the live beat to B");
assert!(to_b.continuity_bearing);
relay_b.on_attestation(t1, &to_b.attestation, to_b.continuity_bearing);
let t2 = t1 + ms(100);
let att101 = origin.emit(&key, AttestedStatus::Ready);
let _lost = relay_c.on_attestation(t2, &att101, true);
let t3 = t2 + ms(400);
relay_c.poll(t3);
relay_b.poll(t3);
assert_eq!(relay_c.upstream_continuity(&key), Some(Continuity::Expired));
assert_eq!(relay_b.upstream_continuity(&key), Some(Continuity::Expired));
let mut a = SensingConsumer::new(K);
a.register_interest(&key, ms(100), t3);
let (_, warm) =
relay_b.register_downstream(&key, DownstreamId::Peer(0xA), ms(100), TTL, root(), t3);
let warm = warm.expect("B's cache warm-starts A");
assert_eq!(warm.attestation.seq, 100);
assert!(!warm.continuity_bearing);
a.on_delivery(t3, &warm);
assert_eq!(a.projected(&key), ProjectedReadiness::Unknown);
relay_c.table.expire(t3);
relay_c.gc_dead_slots(t3);
let (_, warm_b) =
relay_c.register_downstream(&key, DownstreamId::Peer(0xB), ms(100), TTL, root(), t3);
let warm_b = warm_b.expect("C's cache warm-starts B's re-registration");
assert_eq!(warm_b.attestation.seq, 101);
assert!(!warm_b.continuity_bearing);
let out = relay_b.on_attestation(t3, &warm_b.attestation, warm_b.continuity_bearing);
let t4 = t3 + ms(100);
let mut forwarded: Vec<Delivery> = out;
forwarded.extend(relay_b.poll(t4));
let to_a: Vec<&Delivery> = forwarded
.iter()
.filter(|d| d.to == DownstreamId::Peer(0xA))
.collect();
assert!(
!to_a.is_empty(),
"the cached 101 does reach A (down-sampled catch-up)",
);
for delivery in &to_a {
assert!(
!delivery.continuity_bearing,
"hop rule: B must not deliver continuity-bearing while its own \
upstream continuity is Expired",
);
a.on_delivery(t4, delivery);
}
assert_eq!(
a.projected(&key),
ProjectedReadiness::Unknown,
"multi-hop cache laundering: A projected optimism from a dead stream",
);
let t5 = t4 + ms(100);
let att102 = origin.emit(&key, AttestedStatus::Ready);
let out_c = relay_c.on_attestation(t5, &att102, true);
let to_b = out_c
.iter()
.find(|d| d.to == DownstreamId::Peer(0xB))
.expect("C forwards the live beat to B");
assert!(to_b.continuity_bearing, "C is Established again");
let out_b = relay_b.on_attestation(t5, &to_b.attestation, to_b.continuity_bearing);
let to_a = out_b
.iter()
.find(|d| d.to == DownstreamId::Peer(0xA))
.expect("B forwards the live beat to A");
assert!(to_a.continuity_bearing, "B is Established again");
a.on_delivery(t5, to_a);
assert_eq!(a.projected(&key), ProjectedReadiness::Ready);
}
}