Principe RS-7 : « dès qu'on build un truc, plus personne n'a à le rebuild —
la seule chose à faire est l'optimisation. » (nexus/RepoVerse)
- bion-vc : horloges vectorielles + MvReg fork-visible (LA spec
xion-relativiste-v0 enfin codée — CRDT testé par permutations)
- bion-triplet : l'Adressage Génératif (gen_hash BLAKE3, coords, résidu ;
résidu vide quand déjà-su ; align décidable au bit)
- bion-tsoinlog: journal append-only rejouable (CRC32 maison, crash-recovery)
- bion-kv : magasin clé-valeur bitcask (compaction atomique, tombstones)
- bion-regex : moteur Thompson NFA linéaire (jamais exponentiel — Russ Cox)
- bion-git : mini-git content-addressed (SHA-1 maison + vecteurs officiels,
branches divergentes = le fork visible)
129 tests verts, clippy 0 warning, doc française = chaque bion est un cours.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bion-vc — horloges vectorielles + Multi-Value Register « fork visible »
Quoi
La brique causale du xerboxion, std-only, zéro dépendance, zéro unsafe :
VectorClock— l'horloge logique canonique (Fidge/Mattern) :increment(node),merge(&other)(max composante par composante),observe(&other, node)(règle de réception complète), et la comparaison causalecausality()→Before | After | Concurrent | Equal.PartialOrdest implémenté honnêtement :partial_cmprendNonepour deux horloges concurrentes, parce que l'ordre causal est partiel — c'est toute la leçon.Stamped<T>— une valeur + son estampille causale (l'enveloppe du tsoin, §2 de la spec).MvReg<T>— le Multi-Value Register :set()(écrasement causal uniquement — de ce que l'écrivain a vu),apply()/merge()qui gardent les branches concurrentes,values()/branches()/is_forked()pour les exposer,resolve()pour fermer un fork explicitement avec un VC qui domine toutes les branches.- Sérialisation texte stable (
to_text/from_text, formats gelésa:2,b:1etmvr1), sans serde : deux répliques convergées produisent le même texte, octet pour octet.
Pourquoi
C'était l'algo manquant du projet : la spec xion-relativiste-v0
(resources/papers/xion-relativiste-v0.md de my_website2) gèle la décision RS-7 —
Divergence = branche, retrouvaille = merge, conflit = fork visible. Jamais d'écrasement silencieux.
— mais personne ne l'avait codée. La réplication actuelle du labo fait du LWW par horloge
murale (StateReplicationController, savedAt/cmpAt()), qui jette silencieusement une
des deux écritures concurrentes. Ce bion est l'arbitre de remplacement du chemin de
migration §6 de la spec : le merge devient un CRDT (commutatif, associatif, idempotent —
testé par permutations), l'essaim converge sans coordinateur, et aucune branche ne meurt
sans un acte explicite.
Exemple
use bion_vc::{MvReg, Causality, VectorClock};
// Deux répliques divergent : chacune écrit « sa » valeur du même point.
let mut bord = MvReg::new();
bord.set("cubion-bord", "cap sur Europe".to_string());
let mut sol = MvReg::new();
sol.set("cubion-sol", "cap sur Titan".to_string());
// Retrouvailles : merge. Personne ne perd rien → fork VISIBLE.
bord.merge(&sol);
assert!(bord.is_forked());
assert_eq!(bord.values().len(), 2);
// Fermer le fork est un acte explicite, tracé, qui domine les deux branches.
bord.resolve("cubion-bord", |branches| {
let mut caps: Vec<&str> = branches.iter().map(|b| b.value.as_str()).collect();
caps.sort();
caps.join(" PUIS ")
});
assert!(!bord.is_forked());
// Et l'horloge seule, pour estampiller n'importe quoi d'autre :
let mut vc = VectorClock::new();
vc.increment("moi");
assert_eq!(vc.causality(&VectorClock::new()), Causality::After);
Liens build-your-own-x
Le dépôt build-your-own-x n'a pas (encore) de section « Build your own CRDT » — ce bion en tient lieu, depuis les principes, avec les sources primaires qu'un tel tutoriel citerait :
- Lamport, Time, Clocks, and the Ordering of Events in a Distributed System, CACM 1978 — le happened-before.
- Fidge 1988, Mattern 1989 — le vector clock qui capture la causalité complète.
- Shapiro, Preguiça, Baquero, Zawirski, Conflict-free Replicated Data Types, SSS 2011 — les propriétés CRDT et la spec du MV-Register.
- DeCandia et al., Dynamo, SOSP 2007 — les « siblings » : le fork visible en production depuis 2007.
Parents dans build-your-own-x : « Build your own Git » (le merge à trois voies et les branches visibles sont le même geste) et « Build your own Database » (la réplication).
Comment l'optimiser (l'invitation au fork)
L'API est gelée ; tout le reste est à toi. Pistes réelles, dans l'ordre du §7 de la spec :
- Compaction des VC — un VC croît en O(n) nœuds rencontrés. À grande échelle : deltas de VC, dotted version vectors (Preguiça et al. 2010), ou VC hiérarchiques par agrégat. Le format texte réserve la place (c'est une map : ajoute des nœuds composites).
applyen O(n²) sur le nombre de branches — correct et simple ; si un point accumule des centaines de forks non résolus, indexer les branches par nœud dominant.- Interner les ids de nœuds (
Rc<str>/index dans un registre) au lieu deStringpar entrée — le clone de VC est aujourd'hui la seule allocation chaude. - GC des branches — un MVR n'oublie jamais tout seul (c'est voulu) : une politique de rétention/archivage se construit au-dessus, jamais dedans.
Règle du fork : garde to_text/from_text compatibles (rétrocompatibilité éternelle) —
un format v2 porte un nouvel en-tête, il ne mute jamais v1.
cargo test -p bion-vc
Ne pas nuire. Aucune montre n'a raison contre l'autre ; aucune branche ne meurt en silence.