================================================================================
  OC-DISCOVERY : ARCHITECTURE CIBLE — RÉSEAU DHT SANS NATIFS
  Vision d'évolution long terme, issue d'une analyse comparative
================================================================================

Rédigé à partir de l'analyse de l'architecture actuelle et de la discussion
comparative avec Tapestry, Kademlia, EigenTrust et les systèmes de réputation
distribués.

Référence : DECENTRALIZED_SYSTEMS_COMPARISON.txt §9


================================================================================
1. MOTIVATION
================================================================================

L'architecture actuelle (node → indexer → native indexer) est robuste et bien
adaptée à une phase précoce du réseau. Ses limites à l'échelle sont :

  - Pool de natives statique au démarrage → dépendance à la configuration
  - Cache local des natives = point de défaillance unique (perte = pool vide)
  - Consensus inter-natives bloquant (~7s) déclenché à chaque bootstrap node
  - État O(N indexers) par native → croît linéairement avec le réseau
  - Nœuds privilégiés structurellement → SPOFs relatifs

La cible décrite ici supprime la notion de native indexer en tant que tier
architectural. Le réseau devient plat : indexers et nodes sont des acteurs
de même nature, différenciés uniquement par leur rôle volontaire.


================================================================================
2. PRINCIPES FONDAMENTAUX
================================================================================

  P1. Aucun nœud n'est structurellement privilégié.
  P2. La confiance est un produit du temps et de la vérification, pas d'un arbitre.
  P3. Les claims d'un acteur sont vérifiables indépendamment par tout pair.
  P4. La réputation émerge du comportement collectif, pas d'un signalement central.
  P5. La DHT est une infrastructure neutre — elle stocke des faits, pas des jugements.
  P6. La configuration statique n'existe plus au runtime — seulement au bootstrap.


================================================================================
3. RÔLES
================================================================================

3.1 Node
--------
Consommateur du réseau. Démarre, sélectionne un pool d'indexers via DHT,
heartbeat ses indexers, accumule des scores localement. Ne publie rien en
routine. Participe aux challenges de consensus à la demande.

3.2 Indexer
-----------
Acteur volontaire. S'inscrit dans la DHT à la naissance, maintient son record,
sert le trafic des nodes (heartbeat, Publish, Get). Déclare ses métriques dans
chaque réponse heartbeat. Maintient un score agrégé depuis ses nodes connectés.

  Différence avec l'actuel : l'indexer n'a plus de lien avec une native.
  Il est autonome. Son existence dans le réseau est prouvée par son record DHT
  et par les nodes qui le contactent directement.

3.3 Nœud DHT infrastructure (ex-native)
----------------------------------------
N'importe quel nœud suffisamment stable peut maintenir la DHT sans être un
indexer. C'est une configuration, pas un type architectural : `dht_mode: server`.
Ces nœuds maintiennent les k-buckets Kademlia et stockent les records des
indexers. Ils ne connaissent pas le trafic node↔indexer et ne l'orchestrent pas.


================================================================================
4. BOOTSTRAP D'UN NODE
================================================================================

4.1 Entrée dans le réseau
-------------------------
Le node démarre avec 1 à 3 adresses de nœuds DHT connus (bootstrap peers).
Ce sont les seules informations statiques nécessaires. Ces peers n'ont pas de
rôle sémantique — ils servent uniquement à entrer dans l'overlay DHT.

4.2 Découverte du pool d'indexers
----------------------------------

  Node → DHT.FindProviders(hash("/opencloud/indexers"))
       → reçoit une liste de N candidats avec leurs records

Sélection du pool initial :

  1. Filtre latence   : ping < seuil → proximité réseau réelle
  2. Filtre fill rate : préférer les indexers moins chargés
  3. Tirage pondéré   : probabilité ∝ (1 - fill_rate), courbe w(F) = F×(1-F)
                        indexer à 20% charge → très probable
                        indexer à 80% charge → peu probable
  4. Filtre diversité : subnet /24 différent pour chaque entrée du pool

Aucun consensus nécessaire à cette étape. Le node démarre avec une tolérance
basse (voir §7) — il accepte des indexers imparfaits et les évalue au fil du temps.


================================================================================
5. REGISTRATION D'UN INDEXER DANS LA DHT
================================================================================

À la naissance, l'indexer publie son record DHT :

  clé   : hash("/opencloud/indexers")          ← clé fixe, connue de tous
  valeur: {
    multiaddr   : <adresse réseau>,
    region      : <subnet /24>,
    capacity    : <maxNodesConn>,
    fill_rate   : <float 0-1>,                 ← auto-déclaré, vérifiable
    peer_count  : <int>,                       ← auto-déclaré, vérifiable
    peers       : [hash(nodeID1), ...],        ← liste hashée des nodes connectés
    born_at     : <timestamp>,
    sig         : <signature clé indexer>,     ← non-forgeable (PSK context)
  }

Le record est rafraîchi toutes les ~60s (avant expiration du TTL).
Si l'indexer tombe : TTL expire → disparaît de la DHT automatiquement.

La peer list est hashée pour la confidentialité mais reste vérifiable :
un challenger peut demander directement à un node s'il est connecté à cet indexer.


================================================================================
6. PROTOCOLE HEARTBEAT — QUESTION ET RÉPONSE
================================================================================

Le heartbeat devient bidirectionnel : le node pose des questions, l'indexer
répond avec ses déclarations courantes.

6.1 Structure
-------------

  Node → Indexer :
  {
    ts        : now,
    challenge : <optionnel, voir §8>
  }

  Indexer → Node :
  {
    ts           : now,
    fill_rate    : 0.42,
    peer_count   : 87,
    cached_score : 0.74,        ← score agrégé depuis tous ses nodes connectés
    challenge_response : {...}  ← si challenge présent dans la requête
  }

Le heartbeat normal (sans challenge) est quasi-identique à l'actuel en poids.
Le cached_score indexer est mis à jour progressivement par les feedbacks reçus.

6.2 Le cached_score de l'indexer
---------------------------------
L'indexer agrège les scores que ses nodes connectés lui communiquent
(implicitement via le fait qu'ils restent connectés, ou explicitement lors
d'un consensus). Ce score lui donne une vision de sa propre qualité réseau.

Un node peut comparer son score local de l'indexer avec le cached_score déclaré.
Une forte divergence est un signal d'alerte.

  Score local node : 0.40   ← cet indexer est médiocre pour moi
  Cached score     : 0.91   ← il se prétend excellent globalement
  → déclenche un challenge de vérification


================================================================================
7. MODÈLE DE CONFIANCE PROGRESSIVE
================================================================================

7.1 Cycle de vie d'un node
---------------------------

  Naissance
    → tolérance basse : accepte presque n'importe quel indexer du DHT
    → switching cost faible : peu de contexte accumulé
    → minScore ≈ 20% (dynamicMinScore existant, conservé)

  Quelques heures
    → uptime s'accumule sur chaque indexer connu
    → scores se stabilisent
    → seuil de remplacement qui monte progressivement

  Long terme (jours)
    → pool stable, confiance élevée sur les indexers connus
    → switching coûteux mais déclenché sur déception franche
    → minScore ≈ 80% (maturité)

7.2 Modèle sous-jacent : beta distribution implicite
------------------------------------------------------

  α = succès cumulés  (heartbeats OK, probes OK, challenges réussis)
  β = échecs cumulés  (timeouts, probes échoués, challenges ratés)

  confiance = α / (α + β)

  Nouveau indexer   : α=0, β=0   → prior neutre, tolérance basse
  Après 10 jours    : α élevé    → confiance stable, seuil de switch élevé
  Déception franche : β monte    → confiance chute → switch déclenché

7.3 Ce que "décevoir" signifie
--------------------------------

  Heartbeat rate     → trop de timeouts → fiabilité en baisse
  Bandwidth probe    → chute sous déclaré → dégradation ou mensonge
  Fill rate réel     → supérieur au déclaré → indexer surchargé ou malhonnête
  Challenge échoué   → peer déclaré absent du réseau → claim invalide
  Latence            → dérive progressive → qualité réseau dégradée
  Cached_score gonflé → divergence forte avec score local → suspicion


================================================================================
8. VÉRIFICATION DES CLAIMS — TROIS COUCHES
================================================================================

8.1 Couche 1 : passive (chaque heartbeat, 60s)
-----------------------------------------------
Mesures automatiques, zéro coût supplémentaire.

  - RTT du heartbeat          → latence directe
  - fill_rate déclaré         → tiny payload dans la réponse
  - peer_count déclaré        → tiny payload
  - cached_score indexer      → comparé au score local

8.2 Couche 2 : sampling actif (1 heartbeat sur N)
--------------------------------------------------
Vérifications périodiques, asynchrones, légères.

  Tous les 5 HB (~5min)  : spot-check 1 peer aléatoire (voir §8.4)
  Tous les 10 HB (~10min): vérification diversité subnet (lookups DHT légers)
  Tous les 15 HB (~15min): bandwidth probe (transfert réel, protocole dédié)

8.3 Couche 3 : consensus (événementiel)
-----------------------------------------
Déclenché sur : admission d'un nouvel indexer dans le pool, ou suspicion détectée.

  Node sélectionne une claim vérifiable de l'indexer cible X
  Node vérifie lui-même
  Node demande à ses indexers de confiance : "vérifiez cette claim sur X"
  Chaque indexer vérifie indépendamment
  Convergence des résultats → X est honnête → admission
  Divergence               → X est suspect → rejet ou probation

  Le consensus est léger : quelques contacts out-of-band, pas de round bloquant.
  Il n'est pas continu — il est événementiel.

8.4 Vérification out-of-band (pas de DHT writes par les nodes)
----------------------------------------------------------------
Les nodes ne publient PAS de contact records continus dans la DHT.
Cela éviterait N×M records à rafraîchir (coût DHT élevé à l'échelle).

À la place, lors d'un challenge :

  Challenger sélectionne 2-3 peers dans la peer list déclarée par X
  → contacte ces peers directement : "es-tu connecté à indexer X ?"
  → réponse directe (out-of-band, pas via DHT)
  → vérification sans écriture DHT

L'indexer ne peut pas faire répondre "oui" à des peers qui ne lui sont pas
connectés. La vérification est non-falsifiable et sans coût DHT.

8.5 Pourquoi X ne peut pas tricher
------------------------------------
X ne peut pas coordonner des réponses différentes vers des challengers
simultanés. Chaque challenger contacte indépendamment les mêmes peers.
Si X ment sur sa peer list :

  - Challenger A contacte peer P → "non, pas connecté à X"
  - Challenger B contacte peer P → "non, pas connecté à X"
  - Consensus : X ment → score chute chez tous les challengers
  - Effet réseau : progressivement, X perd ses connections
  - Peer list DHT se vide → claims futures encore moins crédibles


================================================================================
9. EFFET RÉSEAU SANS SIGNALEMENT CENTRAL
================================================================================

Un node qui pénalise un indexer n'envoie aucun "rapport" à quiconque.
Ses actions locales produisent l'effet réseau par agrégation :

  Node baisse le score de X      → X reçoit moins de trafic de ce node
  Node switche vers Y            → X perd un client
  Node refuse les challenges X   → X ne peut plus participer aux consensus

Si 200 nodes font pareil :

  X perd la majorité de ses connections
  Sa peer list DHT se vide (peers contactés directement disent "non")
  Son cached_score s'effondre (peu de nodes restent)
  Les nouveaux nodes qui voient X dans la DHT obtiennent des challenges échoués
  X est naturellement exclu sans aucune décision centrale

Inversement, un indexer honnête voit ses scores monter sur tous ses nodes
connectés, sa peer list se densifier, ses challenges réussis systématiquement.
Sa réputation est un produit observable et vérifiable.


================================================================================
10. RÉSUMÉ DE L'ARCHITECTURE
================================================================================

  DHT          → annuaire neutre, vérité des records indexers
                  maintenu par tout nœud stable (dht_mode: server)

  Indexer      → acteur volontaire, s'inscrit, maintient ses claims,
                  sert le trafic, accumule son propre score agrégé

  Node         → consommateur, score passif + sampling + consensus léger,
                  confiance progressive, switching adaptatif

  Heartbeat    → métronome 60s + vecteur de déclarations légères + challenge optionnel

  Consensus    → événementiel, multi-challengers indépendants,
                  vérification out-of-band sur claims DHT

  Confiance    → beta implicite, progressive, switching cost croissant avec l'âge

  Réputation   → émerge du comportement collectif, aucun arbitre central

  Bootstrap    → 1-3 peers DHT connus → seule configuration statique nécessaire


================================================================================
11. TRAJECTOIRE DE MIGRATION
================================================================================

  Phase 1 (actuel)
    Natives statiques, pool indexers dynamique, consensus inter-natives
    → robuste, adapté à la phase précoce

  Phase 2 (intermédiaire)
    Pool de natives dynamique via DHT (bootstrap + gossip)
    Même protocole natif, juste la découverte devient dynamique
    → supprime la dépendance à la configuration statique des natives
    → voir DECENTRALIZED_SYSTEMS_COMPARISON.txt §9.2

  Phase 3 (cible)
    Architecture décrite dans ce document
    Natives disparaissent en tant que tier architectural
    DHT = infrastructure, indexers = acteurs autonomes
    Scoring et consensus entièrement côté node
    → aucun nœud privilégié, scalabilité O(log N)

  La migration Phase 2 → Phase 3 est une refonte du plan de contrôle.
  Le plan de données (heartbeat node↔indexer, Publish, Get) est inchangé.
  Les primitives libp2p (Kademlia DHT, GossipSub) sont déjà présentes.


================================================================================
12. PROPRIÉTÉS DU SYSTÈME CIBLE
================================================================================

  Scalabilité        O(log N) — routage DHT Kademlia
  Résilience         Pas de SPOF structurel, TTL = seule source de vérité
  Confiance          Progressive, vérifiable, émergente
  Sybil resistance   PSK — seuls les nœuds avec la clé peuvent publier
  Cold start         Tolérance basse initiale, montée progressive (existant)
  Honnêteté          Claims vérifiables out-of-band, non-falsifiables
  Décentralisation   Aucun nœud ne connaît l'état global complet

================================================================================
