53dbdf0f1d
Workspace en 4 ejes (core/modules/apps/shared):
- core/: 24 crates de arje (Init systemd-compatible: ente-card, ente-zero,
ente-kernel, ente-bus, ente-cas, ente-soma, ente-wasm, ente-snapshot,
ente-brain, ente-echo, ente-policy-provider, + 12 crates *-compat)
- modules/semantic_dht/: 5 crates de minga (minga-core con AST/CAS/MST,
minga-p2p con libp2p Kad, minga-store, minga-vfs, minga-cli)
- modules/ui_engine/: 11 crates de yahweh (libs/{core,theme,bus,providers},
widgets/{tree,splitter,tabs,tiled,container_core,text_input})
- apps/: 5 crates de yahweh (file_explorer, database_explorer, text_viewer,
image_viewer, yahweh-shell)
- shared_wit/protocol.wit: handshake/lifecycle inicial
Cargo.toml unificado: thiserror bumped a 2 (transparente para arje), tokio
"full", paths intra-workspace de yahweh redirigidos a su nueva ubicación.
cargo check --workspace: 0 errores, 17 warnings (dead code preexistente).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
2.4 KiB
Rust
90 lines
2.4 KiB
Rust
//! Harness in-memory determinístico para correr dos `SyncSession`s
|
|
//! una contra la otra y verificar invariantes del protocolo.
|
|
|
|
use std::collections::VecDeque;
|
|
|
|
use crate::message::Message;
|
|
use crate::session::SyncSession;
|
|
|
|
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
|
pub struct SyncStats {
|
|
pub challenges: usize,
|
|
pub hellos: usize,
|
|
pub probe_reqs: usize,
|
|
pub probe_ress: usize,
|
|
pub fetches: usize,
|
|
pub delivers: usize,
|
|
pub attest_pushes: usize,
|
|
pub dones: usize,
|
|
}
|
|
|
|
impl SyncStats {
|
|
fn record(&mut self, m: &Message) {
|
|
match m {
|
|
Message::Challenge { .. } => self.challenges += 1,
|
|
Message::Hello { .. } => self.hellos += 1,
|
|
Message::ProbeReq { .. } => self.probe_reqs += 1,
|
|
Message::ProbeRes { .. } => self.probe_ress += 1,
|
|
Message::Fetch { .. } => self.fetches += 1,
|
|
Message::Deliver { .. } => self.delivers += 1,
|
|
Message::AttestPush { .. } => self.attest_pushes += 1,
|
|
Message::Done => self.dones += 1,
|
|
}
|
|
}
|
|
|
|
pub fn total(&self) -> usize {
|
|
self.challenges
|
|
+ self.hellos
|
|
+ self.probe_reqs
|
|
+ self.probe_ress
|
|
+ self.fetches
|
|
+ self.delivers
|
|
+ self.attest_pushes
|
|
+ self.dones
|
|
}
|
|
}
|
|
|
|
/// Ejecuta la sincronización entre dos sesiones hasta convergencia.
|
|
///
|
|
/// Pánico si la conversación termina sin que ambas partes alcancen
|
|
/// `is_done()` — eso sería un deadlock del protocolo y una regresión.
|
|
pub fn run_sync(a: &mut SyncSession, b: &mut SyncSession) -> SyncStats {
|
|
let mut from_a: VecDeque<Message> = VecDeque::new();
|
|
let mut from_b: VecDeque<Message> = VecDeque::new();
|
|
let mut stats = SyncStats::default();
|
|
|
|
from_a.extend(a.start());
|
|
from_b.extend(b.start());
|
|
|
|
loop {
|
|
let mut progress = false;
|
|
|
|
if let Some(msg) = from_a.pop_front() {
|
|
stats.record(&msg);
|
|
for out in b.handle(msg) {
|
|
from_b.push_back(out);
|
|
}
|
|
progress = true;
|
|
}
|
|
|
|
if let Some(msg) = from_b.pop_front() {
|
|
stats.record(&msg);
|
|
for out in a.handle(msg) {
|
|
from_a.push_back(out);
|
|
}
|
|
progress = true;
|
|
}
|
|
|
|
if !progress {
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert!(
|
|
a.is_done() && b.is_done(),
|
|
"deadlock: sync terminó sin que ambos peers cerraran"
|
|
);
|
|
|
|
stats
|
|
}
|