@startuml 22_failure_both_natives
title F4 — Panne des 2 natifs → fallback pool pré-validé

participant "Node" as N
participant "Indexer A\\n(vivant)" as IA
participant "Indexer B\\n(vivant)" as IB
participant "Native A\\n(crashé)" as NA
participant "Native B\\n(crashé)" as NB

note over N: Pool actif : StaticIndexers = [IA, IB]\\nStaticNatives = [NA, NB]\\nAdmittedAt[IA] et AdmittedAt[IB] posés (stables)

== Panne simultanée NA et NB ==
NA ->x N: stream reset
NB ->x N: stream reset

N -> N: AfterDelete(NA) + AfterDelete(NB)\\nStaticNatives = {} (vide)

== replenishNativesFromPeers (sans résultat) ==
N -> N: fetchNativeFromNatives() → aucun natif vivant
N -> IA: GET /opencloud/indexer/natives/1.0
IA --> N: GetNativesResponse{Natives:[NA,NB]}
note over N: NA et NB connus mais non joignables.\\nAucun nouveau natif trouvé.

== Fallback : pool d'indexeurs conservé ==
note over N: isFallback = true\\nStaticIndexers conservé tel quel [IA, IB]\\n(dernier pool validé avec AdmittedAt != zero)\\nRisque D19 atténué : quorum natif = 0 → fallback accepté

note over N: Heartbeats IA et IB continuent normalement.\\nPool d'indexeurs opérationnel sans natifs.

N -> IA: SendHeartbeat /opencloud/heartbeat/1.0 (continue)
N -> IB: SendHeartbeat /opencloud/heartbeat/1.0 (continue)

== retryLostNative (30s ticker) ==
loop toutes les 30s
    N -> N: retryLostNative()\\ntente reconnexion NA et NB
    N -> NA: dial (échec)
    N -> NB: dial (échec)
    note over N: Retry sans résultat.\\nPool indexeurs maintenu en fallback.
end

== Reprise natifs ==
NA -> NA: redémarrage
NB -> NB: redémarrage

N -> NA: dial (succès)
N -> NA: SendHeartbeat /opencloud/heartbeat/1.0
N -> NB: SendHeartbeat /opencloud/heartbeat/1.0
note over N: StaticNatives = [NA, NB] restauré\\nisFallback = false

== Re-consensus pool indexeurs (optionnel) ==
par Consensus Phase 1
    N -> NA: /opencloud/native/consensus/1.0\\nConsensusRequest{Candidates:[IA,IB]}
    NA --> N: ConsensusResponse{Trusted:[IA,IB]}
else
    N -> NB: /opencloud/native/consensus/1.0
    NB --> N: ConsensusResponse{Trusted:[IA,IB]}
end par

note over N: Pool [IA,IB] reconfirmé.\\nisFallback = false. AdmittedAt[IA,IB] rafraîchi.

@enduml
