@startuml 23_failure_native_plus_indexer
title F5 — Panne combinée : 1 natif + 1 indexeur

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

note over N: Pool nominal : StaticIndexers=[IA,IB], StaticNatives=[NA,NB]

== Pannes simultanées NB + IB ==
NB ->x N: stream reset
IB ->x N: stream reset

N -> N: AfterDelete(NB) — StaticNatives = [NA]
N -> N: AfterDelete(IB) — StaticIndexers = [IA]

== Replenish natif (1 vivant) ==
N -> N: replenishNativesFromPeers()
N -> NA: GET /opencloud/native/peers/1.0
NA --> N: GetPeersResponse{Peers:[]} /' NB seul pair, disparu '/
note over N: Aucun natif alternatif.\\nStaticNatives = [NA] — dégradé.

== Replenish indexeur depuis NA ==
par Fetch pool (timeout 6s)
    N -> NA: GET /opencloud/native/indexers/1.0
    NA -> NA: reachableLiveIndexers()\\n(IB absent — heartbeat expiré)
    NA --> N: GetIndexersResponse{Indexers:[IA,IC], FillRates:{IA:0.5,IC:0.3}}
end par

note over N: candidates = [IA, IC]

par Consensus Phase 1 — 1 seul natif vivant (timeout 3s)
    N -> NA: /opencloud/native/consensus/1.0\\nConsensusRequest{Candidates:[IA,IC]}
    NA --> N: ConsensusResponse{Trusted:[IA,IC]}
end par

note over N: IC → 1/1 vote → admis (quorum sur vivants)\\nadmittedAt = time.Now()

par Phase 2 liveness vote
    N -> IA: /opencloud/indexer/consensus/1.0\\nIndexerConsensusRequest{Candidates:[IC]}
    IA -> IA: StreamRecords[ProtocolHB][IC]\\nLastSeen ≤ 120s && LastScore ≥ 30
    IA --> N: IndexerConsensusResponse{Alive:[IC]}
end par

N -> N: replaceStaticIndexers(pool={IA,IC})
N -> IC: SendHeartbeat /opencloud/heartbeat/1.0

note over N: Pool restauré à [IA,IC].\\nMode dégradé : 1 natif seulement.\\nretryLostNative(NB) actif (30s ticker).

== retryLostNative pour NB ==
loop toutes les 30s
    N -> NB: dial (échec)
end

NB -> NB: redémarrage
NB -> NA: heartbeat (mesh natif reconstruit)
N -> NB: dial (succès)
N -> NB: SendHeartbeat /opencloud/heartbeat/1.0
note over N: StaticNatives = [NA,NB] restauré.\\nMode nominal retrouvé.

@enduml
