diff --git a/agents/rap-node-agent/internal/mesh/peer_cache.go b/agents/rap-node-agent/internal/mesh/peer_cache.go index 90533a8..5919b1b 100644 --- a/agents/rap-node-agent/internal/mesh/peer_cache.go +++ b/agents/rap-node-agent/internal/mesh/peer_cache.go @@ -55,6 +55,7 @@ type PeerCacheEntry struct { BestNATType string `json:"best_nat_type,omitempty"` BestPolicyTags []string `json:"best_policy_tags,omitempty"` BestCandidateScore int `json:"best_candidate_score,omitempty"` + BestScoreReasons []string `json:"best_score_reasons,omitempty"` EndpointCandidates []PeerEndpointCandidate `json:"endpoint_candidates,omitempty"` RendezvousLeaseID string `json:"rendezvous_lease_id,omitempty"` RelayNodeID string `json:"relay_node_id,omitempty"` @@ -133,6 +134,7 @@ func NewPeerCache(cfg PeerCacheConfig) *PeerCache { entry.BestNATType = scored[0].Candidate.NATType entry.BestPolicyTags = append([]string{}, scored[0].Candidate.PolicyTags...) entry.BestCandidateScore = scored[0].Score + entry.BestScoreReasons = append([]string{}, scored[0].Reasons...) entry.bestScore = scored[0].Score if strings.TrimSpace(scored[0].Candidate.Address) != "" { entry.Endpoint = strings.TrimSpace(scored[0].Candidate.Address) diff --git a/agents/rap-node-agent/internal/mesh/peer_cache_test.go b/agents/rap-node-agent/internal/mesh/peer_cache_test.go index fa3fd37..9a0c0ad 100644 --- a/agents/rap-node-agent/internal/mesh/peer_cache_test.go +++ b/agents/rap-node-agent/internal/mesh/peer_cache_test.go @@ -151,6 +151,9 @@ func TestPeerCacheAppliesEndpointHealthObservations(t *testing.T) { if entry.BestCandidateID != "node-b-wss" || entry.Endpoint != "https://node-b.example.test:443" { t.Fatalf("peer cache did not apply endpoint observations: %+v", entry) } + if !containsString(entry.BestScoreReasons, "transport:wss") { + t.Fatalf("peer cache did not expose score reasons: %+v", entry.BestScoreReasons) + } } func TestPeerCacheUsesPreferredCorporateEndpointAddress(t *testing.T) { diff --git a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md index d33f508..3fc4115 100644 --- a/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md +++ b/docs/architecture/DISTRIBUTED_FABRIC_NODE_PROTOCOL_PLAN.md @@ -350,6 +350,9 @@ report level for simpler multi-node ingestion and diagnostics. Peer cache construction now applies endpoint health observations when ranking peer endpoint candidates, so recovery and warm-peer decisions see the same degraded-path feedback as VPN fabric-session dialing. +Peer cache snapshots expose best-candidate score reasons, giving diagnostics a +direct explanation for why a QUIC, WebSocket, relay, or fallback endpoint was +chosen. Deliverables: