Dos precisiones para que el registro diga exactamente lo que el código hace: - durable: documentar que `real` es un oráculo INDEPENDIENTE del desembolso FÍSICO al usuario — se incrementa en el ack (punto de entrega externo e irreversible), una vez por retiro entregado, y NUNCA lee la contabilidad interna (value/committed). Cuenta eventos de entrega, no lo que el sistema cree que gastó. El guard usa la contabilidad para decidir; si se corrompe (rollback) se entrega de más y `real` lo atrapa. Ahí vive detección vs prevención. - BOUNDARY.md: CloneDetected es una ALARMA, no una recuperación. El daño de una celda ya ocurrió en el mundo (dinero real entregado); aislar evita que el doble conteo se propague, pero no recupera nada. La compensación vive fuera del sistema, es coordinación, y puede fracasar. Acotado y delatado, sí; reversible, no necesariamente. Para que M4 no lo lea como auto-reparación. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
68 lines
3.6 KiB
Markdown
68 lines
3.6 KiB
Markdown
# BOUNDARY — la frontera del clon (T11c, §D)
|
|
|
|
El límite último del proyecto, dicho sin sobre-reclamo. Respaldado por
|
|
`fencing::tests`.
|
|
|
|
## El teorema de imposibilidad
|
|
|
|
> **Ningún mecanismo local puede detectar un clon silencioso antes de que los
|
|
> clones se comuniquen.**
|
|
|
|
Un dispositivo restaurado a dos copias vivas (VM snapshot, proceso duplicado) que
|
|
comparten `device_id` y celda y **no se comunican**: cada clon cree tener la celda
|
|
entera y puede gastarla. Sin comunicación, no hay forma de saber que el
|
|
presupuesto ya se gastó en la otra copia. Es el mismo **CAP** que el sobregiro
|
|
particionado (`AVAILABILITY.md`), ahora **dentro de una celda**: bajo partición, o
|
|
sacrificas consistencia (doble gasto) o disponibilidad (no gastas). No hay tercera
|
|
opción, y este proyecto no finge tenerla.
|
|
|
|
## Lo mejor posible: fencing por época, enforced en el merge
|
|
|
|
No un servidor central (no existe en la malla), sino el propio `merge`:
|
|
|
|
- Cada arranque de un dispositivo incrementa una **época** monótona, **device-local**
|
|
y persistida en el WAL (§B/`durable.rs`). Device-local **a propósito**: épocas
|
|
globalmente monótonas pedirían consenso, que es justo lo que evitamos.
|
|
- El gasto se indexa por `(device_id, epoch)`.
|
|
- Al fusionar, dos linajes con el mismo `device_id` y **épocas distintas** delatan
|
|
un clon: la época menor es la obsoleta (`MergeOutcome::CloneDetected`).
|
|
|
|
## La garantía real: *bounded + detect*, no *prevent*
|
|
|
|
Honestidad frente al fencing token clásico (Kleppmann): aquél asume un recurso
|
|
**linealizable** que rechaza tokens viejos. La malla no lo tiene, por eso el
|
|
enforcement vive en el `merge` y la garantía es más débil y honesta:
|
|
|
|
| | Sin fencing | Con fencing (T11c) |
|
|
|---|---|---|
|
|
| Doble gasto | silencioso e **ilimitado** | **acotado** a una celda por clon no detectado |
|
|
| Detección | nunca | **al reconectar** (en el merge) |
|
|
|
|
- **No previene** el doble gasto mientras los clones están aislados — es imposible.
|
|
- **Lo acota**: cada clon gasta ≤ su presupuesto de celda ⟹ el sobregiro es ≤ una
|
|
celda (`FencedCell::overspend() ≤ budget`, verificado por `proptest`).
|
|
- **Lo delata**: `CloneDetected` en el merge. El linaje vivo (época mayor) es lo
|
|
único que se propaga como legítimo; los gastos del clon obsoleto quedan aislados.
|
|
|
|
**`CloneDetected` es una ALARMA, no una recuperación.** El daño de una celda **ya
|
|
ocurrió en el mundo**: el clon obsoleto entregó dinero real que no se puede
|
|
des-entregar desde aquí. Aislar sus gastos evita que el doble conteo se propague
|
|
como presupuesto legítimo por la malla, pero **no recupera nada**. La compensación
|
|
(clawback, reverso, alarma humana) es un problema de la **capa de aplicación**,
|
|
vive **fuera** de este sistema, es **coordinación**, y **puede fracasar** (el
|
|
dinero se fue). Acotado y delatado, sí; **reversible, no necesariamente**. M4 no
|
|
debe leer esto como "el sistema se auto-repara".
|
|
|
|
Convierte "silencioso e ilimitado" en "acotado y delatado". Eso es todo lo que un
|
|
sistema coordination-free puede ofrecer aquí — y decirlo así es el resultado.
|
|
|
|
## El terminus honesto (§E)
|
|
|
|
**Seguridad coordination-free módulo un supuesto físico nombrado:** cada celda de
|
|
presupuesto tiene un único escritor durable. Bajo ese supuesto (durabilidad §B +
|
|
réplica-por-dispositivo §C) el certificado de T10 aplica sin coordinación. Cuando
|
|
el supuesto se rompe (clon, §D), el daño está acotado a una celda por clon no
|
|
detectado y se detecta al reconectar. No "seguro pase lo que pase", sino "seguro
|
|
salvo esta condición física, y aquí está exactamente qué pasa cuando se rompe y
|
|
cuánto cuesta".
|