PeerCortex/server/resilience-score.js
Rene Fichtmueller 1ab6f54d10 refactor: extract Phase A modules from server.js (static data + pure logic)
Zero shared mutable state, no I/O -- behavior-preserving, verified via the
smoke-test harness (28/28 endpoints match baseline).

- server/data/*: CITY_COORDS, RIR_DELEGATION_URLS, TIER1_ASNS, IX_CITY_MAP,
  RIR country-code sets, UA constant
- server/aspa-verification/engine.js: the RFC ASPA verification engine
  (hopCheck, verifyUpstream, verifyDownstream, detectValleys, etc.)
- server/resilience-score.js, server/route-leak.js: pure scoring/heuristic
  functions

server.js: 6838 -> 6454 lines. Part of the module-split plan at
~/.claude/plans/linked-riding-newell.md.
2026-07-16 23:19:13 +02:00

76 lines
2.9 KiB
JavaScript

// Weighted: Transit Diversity 30%, Peering Breadth 25%, IXP Presence 20%, Path Redundancy 25%
// Hard cap at 5.0 when single transit provider detected.
// Confidence: HIGH — all inputs cross-validated daily vs RIPE Stat + PeeringDB.
function computeResilienceScore(upstreams, peers, ixConnections, prefixes) {
const upstreamCount = upstreams.length;
const peerCount = peers.length;
const ixCount = [...new Set(ixConnections.map(c => c.ix_id).filter(Boolean))].length;
const prefixCount = prefixes.length;
// Transit Diversity (0-10)
let transitRaw = 0;
if (upstreamCount === 0) transitRaw = 0;
else if (upstreamCount === 1) transitRaw = 2;
else if (upstreamCount === 2) transitRaw = 5;
else if (upstreamCount <= 4) transitRaw = 7;
else transitRaw = 10;
// Peering Breadth (0-10)
let peeringRaw = 0;
if (peerCount >= 100) peeringRaw = 10;
else if (peerCount >= 50) peeringRaw = 8;
else if (peerCount >= 20) peeringRaw = 6;
else if (peerCount >= 5) peeringRaw = 4;
else if (peerCount >= 1) peeringRaw = 2;
// IXP Presence (0-10)
let ixpRaw = 0;
if (ixCount >= 10) ixpRaw = 10;
else if (ixCount >= 6) ixpRaw = 8;
else if (ixCount >= 3) ixpRaw = 6;
else if (ixCount >= 1) ixpRaw = 4;
// Path Redundancy (0-10) — proxy: prefix diversity + upstream + IXP combination
let pathRaw = 0;
if (upstreamCount >= 2 && ixCount >= 1) pathRaw = 10;
else if (upstreamCount >= 2) pathRaw = 7;
else if (ixCount >= 2) pathRaw = 6;
else if (upstreamCount === 1) pathRaw = 3;
else if (prefixCount > 0) pathRaw = 1;
const weighted =
transitRaw * 0.30 +
peeringRaw * 0.25 +
ixpRaw * 0.20 +
pathRaw * 0.25;
const singleTransitCap = upstreamCount === 1;
let score = Math.round(weighted * 10) / 10;
if (singleTransitCap) score = Math.min(score, 5.0);
score = Math.max(1.0, Math.min(10.0, score));
// Only return null if truly no data at all
if (upstreamCount === 0 && peerCount === 0 && ixCount === 0 && prefixCount === 0) {
return null;
}
return {
score,
breakdown: {
transit_diversity: { raw: transitRaw, weighted: Math.round(transitRaw * 0.30 * 10) / 10, upstream_count: upstreamCount },
peering_breadth: { raw: peeringRaw, weighted: Math.round(peeringRaw * 0.25 * 10) / 10, peer_count: peerCount },
ixp_presence: { raw: ixpRaw, weighted: Math.round(ixpRaw * 0.20 * 10) / 10, unique_ixps: ixCount },
path_redundancy: { raw: pathRaw, weighted: Math.round(pathRaw * 0.25 * 10) / 10, prefix_count: prefixCount },
},
single_transit_cap_applied: singleTransitCap,
_provenance: {
source: "RIPE Stat asn-neighbours + PeeringDB netixlan",
validation: "cross-validated",
confidence: "high",
note: "All inputs independently validated daily against external sources",
},
};
}
module.exports = { computeResilienceScore };