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 Definiciones

⎇ 74acdb9dbca5fc2399bce6f3d65a3bf865c01c22 COMPARISON.md Markdown · 52 líneas · 2.9 KB Historia crudo

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

1# COMPARISON — detector (T8) vs escrow (T9)
2
3Los dos mecanismos sobre los **mismos escenarios**, misma cuenta (saldo inicial
4100, invariante `saldo ≥ 0`, slack `S = 100`). Los veredictos de esta tabla son
5exactamente los que verifica `tests/comparison.rs` — ninguno está escrito a mano.
6
7- **Detector (T8):** funde los estados de las réplicas y comprueba el merge
8  (`AccountConfig::haz_coordination`). Detección **reactiva por-estado**.
9- **Escrow (T9):** reparto de presupuestos `[50,50]` (válido: `Σ ≤ 100`); cada
10  réplica gasta local si le cabe (`try_spend`). **Evitación por construcción**.
11
12| # | Escenario | Grafo | Retiros | Detector (T8) | Escrow `[50,50]` (T9) |
13|---|---|---|---|---|---|
14| 1 | conectado, caben | `0—1` | `10,10` | corre libre | **Local** (ambos ≤ 50) |
15| 2 | conectado, sobregiro | `0—1` | `60,60` | coordina | **rebalanceo** (60 > 50) |
16| 3 | **particionado, sobregiro** | `∅` | `60,60` | **corre libre** ⚠️ | **rebalanceo** (60 > 50) |
17| 4 | particionado, caben | `∅` | `10,10` | corre libre | Local |
18
19## La fila 3 es todo el punto de T9
20
21**El detector dice "corre libre" al caso más peligroso.** Con las dos réplicas
22particionadas retirando 60 cada una de una cuenta de 100, el saldo global va a
23`100 − 120 = −20`: viola el invariante. Pero el detector, al codificar una
24restricción **global** por aristas **pares**, se queda sin ninguna arista al
25particionar y no ve el acoplamiento. **Falso-verde: el caso inseguro reportado
26como seguro** — el peor error posible en un consejero de coordinación.
27
28**El escrow lo bloquea correctamente.** El presupuesto de cada réplica es 50; un
29retiro de 60 devuelve `NeedsRebalance{deficit:10}`, **con o sin partición**,
30porque el presupuesto `b_i` es local y su certificado (`Σ b_i ≤ S`) no depende de
31que haya arista. La partición no lo ciega: lo respeta.
32
33## Rendimiento ≠ corrección (R-T9a)
34
35| Reparto | Retiro | Escrow | Nota |
36|---|---|---|---|
37| `[100, 0]` | réplica 1 retira 10 | rebalanceo | reparto malo: la réplica seca coordina de más |
38| `[50, 50]` | réplica 1 retira 10 | Local | reparto equilibrado: cero coordinación |
39
40Ambos repartos son **correctos** (el certificado `valor ≥ K` aguanta los dos); el
41segundo es solo más **eficiente**. La calidad del reparto es un problema de
42optimización sobre el grafo — el trabajo del `BudgetRouter` (`diffuse`) — no de
43corrección. Por eso los tests los separan.
44
45## Lectura
46
47El detector no se borra (sirve como alarma de reconciliación honesta para
48invariantes sin estructura de recurso divisible, R-T9b: unicidad de ID,
49integridad referencial). Pero **deja de ser el consejero de coordinación**: para
50un invariante numérico sobre un recurso conservado, el que evita coordinación de
51verdad —y sin puntos ciegos— es el **escrow** (`escrow.rs`), ruteado por el grafo
52(`router.rs`). Ver `STRONG_RESULT.md` para la corrección del reclamo de T8.

COMPARISON.md

COMPARISON — detector (T8) vs escrow (T9)

Los dos mecanismos sobre los mismos escenarios, misma cuenta (saldo inicial 100, invariante saldo ≥ 0, slack S = 100). Los veredictos de esta tabla son exactamente los que verifica tests/comparison.rs — ninguno está escrito a mano.

#EscenarioGrafoRetirosDetector (T8)Escrow [50,50] (T9)
1conectado, caben0—110,10corre libreLocal (ambos ≤ 50)
2conectado, sobregiro0—160,60coordinarebalanceo (60 > 50)
3particionado, sobregiro∅60,60corre libre ⚠️rebalanceo (60 > 50)
4particionado, caben∅10,10corre libreLocal

La fila 3 es todo el punto de T9

El detector dice "corre libre" al caso más peligroso. Con las dos réplicas particionadas retirando 60 cada una de una cuenta de 100, el saldo global va a 100 − 120 = −20: viola el invariante. Pero el detector, al codificar una restricción global por aristas pares, se queda sin ninguna arista al particionar y no ve el acoplamiento. Falso-verde: el caso inseguro reportado como seguro — el peor error posible en un consejero de coordinación.

El escrow lo bloquea correctamente. El presupuesto de cada réplica es 50; un retiro de 60 devuelve NeedsRebalance{deficit:10}, con o sin partición, porque el presupuesto b_i es local y su certificado (Σ b_i ≤ S) no depende de que haya arista. La partición no lo ciega: lo respeta.

Rendimiento ≠ corrección (R-T9a)

RepartoRetiroEscrowNota
[100, 0]réplica 1 retira 10rebalanceoreparto malo: la réplica seca coordina de más
[50, 50]réplica 1 retira 10Localreparto equilibrado: cero coordinación

Ambos repartos son correctos (el certificado valor ≥ K aguanta los dos); el segundo es solo más eficiente. La calidad del reparto es un problema de optimización sobre el grafo — el trabajo del BudgetRouter (diffuse) — no de corrección. Por eso los tests los separan.

Lectura

El detector no se borra (sirve como alarma de reconciliación honesta para invariantes sin estructura de recurso divisible, R-T9b: unicidad de ID, integridad referencial). Pero deja de ser el consejero de coordinación: para un invariante numérico sobre un recurso conservado, el que evita coordinación de verdad —y sin puntos ciegos— es el escrow (escrow.rs), ruteado por el grafo (router.rs). Ver STRONG_RESULT.md para la corrección del reclamo de T8.