tawasuyu/hifas
Motor en Rust para decidir, con demostración y no a ojo, cuándo un conjunto de réplicas local-first puede operar sin coordinación y cuándo no — y, cuando la respuesta es "sí, dentro de límites", proveer el mecanismo que lo garantiza.
T2: CRDTs GCounter/ResettableRegister + hito M1 de punta a punta
1//! Criterio de éxito del hito M1 (§8): A da 0, B da ≠0, y la localización de B
2//! apunta al ciclo correcto (entre las réplicas 1 y 2).
3
4use sheafsync::cohomology;
5use sheafsync::nerve::ReplicaId;
6use sheafsync::sheaf::Sheaf;
7use sheafsync::verdict::Verdict;
8
9#[test]
10fn corrida_a_corre_libre() {
11 // G-Counter compartido en camino acíclico (stalk = vector ℤ³).
12 let sheaf = Sheaf::constant(3, &[(0, 1), (1, 2)], 3);
13 let coho = cohomology::compute(&sheaf).unwrap();
14 assert_eq!(coho.dim_h1, 0, "el caso monótono no tiene obstrucción");
15 assert_eq!(Verdict::diagnose(&sheaf, &coho), Verdict::RunsFree);
16}
17
18#[test]
19fn corrida_b_coordina_con_nudo_localizado() {
20 // ResettableRegister: enlace doble irreconciliable entre réplicas 1 y 2.
21 let sheaf = Sheaf::constant(3, &[(0, 1), (1, 2), (1, 2)], 1);
22 let coho = cohomology::compute(&sheaf).unwrap();
23 assert_eq!(coho.dim_h1, 1, "el ciclo produce una obstrucción");
24
25 let verdict = Verdict::diagnose(&sheaf, &coho);
26 let knots = match verdict {
27 Verdict::NeedsCoordination { knots } => knots,
28 Verdict::RunsFree => panic!("debería necesitar coordinación"),
29 };
30 assert_eq!(knots.len(), 1, "un único nudo");
31 let knot = &knots[0];
32
33 // El nudo está entre las réplicas 1 y 2, NO involucra a la réplica 0.
34 assert_eq!(knot.replicas, vec![ReplicaId(1), ReplicaId(2)]);
35 // Y son las dos aristas del enlace doble (índices 1 y 2), no la 0.
36 assert_eq!(knot.edges, vec![1, 2]);
37}