gioser

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.

⎇ 100d09cc730498b3b3c104e360166e921f024b14 tests/comparison.rs Rust · 50 lines · 2.3 KB History Who touched what raw

T9c: comparación honesta y corrección del registro (cierra T9) 6eff6f1c3 · Sergio ·

1//! Respaldo de `COMPARISON.md` (T9c): el detector de T8 y el certificador de
2//! escrow de T9 sobre los mismos escenarios. Los veredictos de la tabla del `.md`
3//! son exactamente los que asertan estos tests — nada escrito a mano.
4//!
5//! Cuenta común: saldo inicial 100, invariante `saldo ≥ 0` (slack 100).
6
7use sheafsync::escrow::{Budget, SpendResult};
8use sheafsync::invariant::AccountConfig;
9use sheafsync::oracle::OracleVerdict;
10
11/// Veredicto del DETECTOR de T8 (funde estados y comprueba el merge).
12fn detector(withdrawals: Vec<u64>, edges: Vec<(usize, usize)>) -> OracleVerdict {
13    AccountConfig::new("cmp", 100, withdrawals, edges).haz_coordination()
14}
15
16/// ¿El ESCROW de T9 permite todos los gastos localmente (sin coordinar) con el
17/// reparto dado? `true` = seguro sin coordinación; `false` = alguien pide rebalanceo.
18fn escrow_todo_local(withdrawals: &[u64], split: Vec<i64>) -> bool {
19    let mut budget = Budget::new(split);
20    withdrawals
21        .iter()
22        .enumerate()
23        .all(|(i, &w)| matches!(budget.try_spend(i, w as i64), SpendResult::Local))
24}
25
26#[test]
27fn escenarios_de_comparison_md() {
28    // 1) Conectado, retiros que caben (10/10).
29    assert_eq!(detector(vec![10, 10], vec![(0, 1)]), OracleVerdict::CoordinationFree);
30    assert!(escrow_todo_local(&[10, 10], vec![50, 50]));
31
32    // 2) Conectado, sobregiro (60/60): ambos detectan el problema.
33    assert_eq!(detector(vec![60, 60], vec![(0, 1)]), OracleVerdict::NeedsCoordination);
34    assert!(!escrow_todo_local(&[60, 60], vec![50, 50]));
35
36    // 3) PARTICIONADO, sobregiro (60/60): el detector da FALSO-VERDE...
37    assert_eq!(detector(vec![60, 60], vec![]), OracleVerdict::CoordinationFree);
38    // ...pero el escrow lo bloquea correctamente (60 > presupuesto de 50).
39    assert!(!escrow_todo_local(&[60, 60], vec![50, 50]));
40
41    // 4) Particionado, retiros que caben (10/10): ambos ok.
42    assert_eq!(detector(vec![10, 10], vec![]), OracleVerdict::CoordinationFree);
43    assert!(escrow_todo_local(&[10, 10], vec![50, 50]));
44
45    // 5) Reparto malo [100,0] (R-T9a): retiro 10 en la réplica seca pide
46    //    rebalanceo aunque el slack global sobre — es rendimiento, no corrección.
47    assert!(!escrow_todo_local(&[0, 10], vec![100, 0]));
48    // Con un reparto equilibrado [50,50] el mismo gasto es local.
49    assert!(escrow_todo_local(&[0, 10], vec![50, 50]));
50}