tawasuyu

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.

Rust 24Markdown 15TOML 1358 Sutichaykuna

⎇ 94482d292d072d791f2244b8571bc30c262fde8a src/main.rs Rust · 87 siq'ikuna · 3.4 KB Ñawpa willay Pi imata llamkarqan ch'uya

T2: CRDTs GCounter/ResettableRegister + hito M1 de punta a punta 94482d292 · Sergio ·

1//! Binario de `sheafsync`. Hito M1 (§8): dos corridas de signo opuesto que
2//! prueban el núcleo entero de punta a punta.
3//!
4//! - Corrida A (G-Counter, monótono): compartición acíclica → `H¹ = 0` → corre libre.
5//! - Corrida B (ResettableRegister, no monótono): el reset introduce un enlace
6//!   irreconciliable sobre el dato ya compartido por las réplicas 1 y 2 → ciclo
7//!   localizado → `H¹ ≠ 0` → coordina ahí.
8
9use sheafsync::cell::{Cell, GCounter, ResettableRegister};
10use sheafsync::cohomology::{self, Cohomology};
11use sheafsync::sheaf::Sheaf;
12use sheafsync::verdict::Verdict;
13
14fn main() {
15    println!("sheafsync — hito M1\n");
16    corrida_a();
17    println!();
18    corrida_b();
19}
20
21/// Imprime el veredicto de un haz ya construido.
22fn veredicto(nombre: &str, sheaf: &Sheaf) -> Cohomology {
23    let coho = cohomology::compute(sheaf).expect("haz bien formado");
24    let verdict = Verdict::diagnose(sheaf, &coho);
25    println!(
26        "  cohomología: dim H⁰ = {}, dim H¹ = {}  (rank δ = {}, dim C⁰ = {}, dim C¹ = {})",
27        coho.dim_h0, coho.dim_h1, coho.rank_delta, coho.dim_c0, coho.dim_c1
28    );
29    println!("  veredicto [{nombre}]: {verdict}");
30    coho
31}
32
33/// Corrida A — G-Counter monótono sobre 3 réplicas que comparten en camino.
34///
35/// Cada réplica incrementa solo su casilla y difunde el vector a sus vecinas.
36/// Al fundir por máximo siempre convergen; la compartición es acíclica, así que
37/// no hay obstrucción posible: `H¹ = 0`.
38fn corrida_a() {
39    println!("Corrida A — G-Counter (monótono: {})", GCounter::is_monotone());
40
41    // Demostración del CRDT: tres réplicas incrementan lo suyo y se funden.
42    let mut r0 = GCounter::zeros(3);
43    let mut r1 = GCounter::zeros(3);
44    let mut r2 = GCounter::zeros(3);
45    r0.increment(0, 5);
46    r1.increment(1, 3);
47    r2.increment(2, 7);
48    let fundido = r0.join(&r1).join(&r2);
49    println!(
50        "  merge de las 3 réplicas: {:?}  (valor total = {})",
51        fundido.slots,
52        fundido.value()
53    );
54
55    // Haz: stalk = el vector contador (ℤ³), restricciones = identidad (comparten
56    // el vector completo), topología = camino 0—1—2 (acíclica).
57    let sheaf = Sheaf::constant(3, &[(0, 1), (1, 2)], 3);
58    veredicto("A", &sheaf);
59}
60
61/// Corrida B — ResettableRegister no monótono sobre 3 réplicas en ciclo.
62///
63/// Las réplicas 1 y 2 comparten un registro. El reset (no monótono) impone un
64/// segundo enlace sobre ese mismo dato que no puede reconciliarse globalmente:
65/// forma un ciclo entre 1 y 2. El haz lo detecta y lo localiza ahí.
66fn corrida_b() {
67    println!(
68        "Corrida B — ResettableRegister (monótono: {})",
69        ResettableRegister::is_monotone()
70    );
71
72    // Demostración del CRDT: un reset con valor menor gana por generación.
73    let alto = ResettableRegister::new(10);
74    let mut reseteado = alto.clone();
75    reseteado.reset(0);
76    let fundido = alto.join(&reseteado);
77    println!(
78        "  merge tras reset: value = {} (gen {}) — el reset retracta el 10 previo",
79        fundido.value, fundido.generation
80    );
81
82    // Haz: stalk = valor del registro (escalar), restricciones = identidad.
83    // Aristas: 0—1 (single) y un DOBLE enlace 1—2 (el original + el que fuerza el
84    // reset), irreconciliables → ciclo localizado entre réplicas 1 y 2.
85    let sheaf = Sheaf::constant(3, &[(0, 1), (1, 2), (1, 2)], 1);
86    veredicto("B", &sheaf);
87}