mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-05-12 04:54:42 +00:00
f33801ecb4
## Summary Implements the **Traffic axis** of the repeater usefulness score (#672). Does NOT close #672 — Bridge, Coverage, and Redundancy axes are deferred to follow-up PRs. Adds `usefulness_score` (0..1) to repeater/room node API responses representing what fraction of non-advert traffic passes through this repeater as a relay hop. ## Why traffic-axis-first The issue proposes a 4-axis composite (Bridge, Coverage, Traffic, Redundancy). Bridge/Coverage/Redundancy require betweenness centrality and neighbor graph infrastructure (#773 Neighbor Graph V2). Traffic axis can ship independently using existing path-hop data. ## Remaining work for #672 - Bridge axis (betweenness centrality — depends on #773) - Coverage axis (observer reach comparison) - Redundancy axis (node-removal simulation — depends on #687) - Composite score combining all 4 axes Partial fix for #672. --------- Co-authored-by: meshcore-bot <bot@meshcore.local>
65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
package main
|
|
|
|
import "strings"
|
|
|
|
// GetRepeaterUsefulnessScore returns a 0..1 score representing what
|
|
// fraction of non-advert traffic in the store passes through this
|
|
// repeater as a relay hop. Issue #672 (Traffic axis only — bridge,
|
|
// coverage, and redundancy axes are deferred to follow-up work).
|
|
//
|
|
// Numerator: count of non-advert StoreTx entries indexed under
|
|
// pubkey in byPathHop.
|
|
// Denominator: total non-advert StoreTx entries in the store
|
|
// (sum of byPayloadType for all keys != payloadTypeAdvert).
|
|
//
|
|
// Returns 0 when there is no non-advert traffic, the pubkey is empty,
|
|
// or the repeater never appears as a relay hop. Scores are clamped to
|
|
// [0,1] for defensive bounds.
|
|
//
|
|
// Cost: O(N) over byPayloadType keys (typically <20) plus the per-hop
|
|
// slice for pubkey. Cheap relative to the per-request enrichment loop
|
|
// in handleNodes; if it ever shows up in profiles, denominator can be
|
|
// memoized off store invalidation.
|
|
func (s *PacketStore) GetRepeaterUsefulnessScore(pubkey string) float64 {
|
|
if pubkey == "" {
|
|
return 0
|
|
}
|
|
key := strings.ToLower(pubkey)
|
|
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
|
|
// Denominator: total non-advert packets.
|
|
totalNonAdvert := 0
|
|
for pt, list := range s.byPayloadType {
|
|
if pt == payloadTypeAdvert {
|
|
continue
|
|
}
|
|
totalNonAdvert += len(list)
|
|
}
|
|
if totalNonAdvert == 0 {
|
|
return 0
|
|
}
|
|
|
|
// Numerator: this repeater's non-advert hop appearances.
|
|
relayed := 0
|
|
for _, tx := range s.byPathHop[key] {
|
|
if tx == nil {
|
|
continue
|
|
}
|
|
if tx.PayloadType != nil && *tx.PayloadType == payloadTypeAdvert {
|
|
continue
|
|
}
|
|
relayed++
|
|
}
|
|
|
|
score := float64(relayed) / float64(totalNonAdvert)
|
|
if score < 0 {
|
|
return 0
|
|
}
|
|
if score > 1 {
|
|
return 1
|
|
}
|
|
return score
|
|
}
|