# InternetPressure.io — scoring configuration (single source of truth for the pressure engine). # Everything here is hot-reloadable by the engine (re-read every cycle) and editable from /admin. # Weights must sum to 1.0. Nothing in the application code hard-codes these values. version: 1 pressure_weights: routing: 0.25 latency: 0.20 dns: 0.15 availability: 0.15 http_tls: 0.10 path: 0.10 corroboration: 0.05 levels: - { max: 10, id: calm, label: "Exceptionally calm" } - { max: 25, id: normal, label: "Normal" } - { max: 40, id: elevated, label: "Elevated" } - { max: 55, id: stressed, label: "Stressed" } - { max: 70, id: high, label: "Highly stressed" } - { max: 85, id: severe, label: "Severe disruption" } - { max: 100, id: extreme, label: "Extreme Internet event" } engine: cycle_seconds: 15 # how often the global score is recomputed (≈ 20 000 targets × 8 probes per cycle) window_seconds: 120 # "current" window for probe signals bgp_window_seconds: 60 # "current" window for BGP rates baseline_days: 7 # trailing baseline horizon baseline_exclude_seconds: 600 # most recent data excluded from the baseline (so an incident doesn't baseline itself) baseline_min_samples: 12 # 5-minute buckets; below this the signal is "weak coverage" and its weight is damped (0 under 20 %) seasonality: hour_of_day # baseline restricted to ±1h same hour of day when enough history exists seasonality_min_days: 3 # …otherwise plain trailing window z_clip_low: -3.0 z_clip_high: 8.0 z_anomaly: 3.0 # a pair (probe,target) is abnormal above this robust z saturation_k: 1.2 # score = 100 * (1 - exp(-k * stress)) / (1 - exp(-k)) — concavity of stress → score z_stress_start: 1.0 # pair stress ramps from 0 at this robust z … z_stress_full: 6.0 # … to 1 at this robust z availability_amplification: 8 # share of importance-weighted targets down × this = availability stress (1/8 down → 100) rate_scale: 0.25 # failure-rate excess over baseline that yields full stress (25 % of checks) loss_scale: 0.10 # packet-loss excess over baseline that yields full stress (10 %) min_probes_for_scoring: 2 # self-exclusion: below this the engine freezes and reports internal degradation probe_fresh_seconds: 180 # a probe is "fresh" if we received a batch in the last N seconds probe_local_failure_ratio: 0.8 # if ≥80 % of a probe's targets fail at once, the probe is excluded (its own uplink is down) bgp_fresh_seconds: 120 # Per-component stress recipe. Each signal contributes weight × f(robust_z or ratio) to the component "stress", # which is then saturated into 0–100. The `label` is what the explainability UI shows. components: latency: signals: - { id: ttfb_z, label: "HTTP time-to-first-byte vs baseline", weight: 0.35 } - { id: tcp_z, label: "TCP connect latency vs baseline", weight: 0.25 } - { id: rtt_z, label: "ICMP round-trip time vs baseline", weight: 0.25 } - { id: loss, label: "Packet loss", weight: 0.15 } dns: signals: - { id: dns_fail_rate, label: "DNS SERVFAIL / timeout rate", weight: 0.45 } - { id: dns_latency_z, label: "DNS lookup latency vs baseline", weight: 0.30 } - { id: resolver_disagreement, label: "Resolver disagreement", weight: 0.25 } availability: signals: - { id: target_down_corroborated, label: "Targets failing from ≥2 probe regions", weight: 0.70 } - { id: fail_rate_z, label: "Failure rate vs baseline", weight: 0.30 } http_tls: signals: - { id: http_5xx_rate, label: "HTTP 5xx rate", weight: 0.35 } - { id: tls_fail_rate, label: "TLS handshake failures", weight: 0.35 } - { id: reset_timeout_rate, label: "Connection resets / timeouts", weight: 0.30 } path: signals: - { id: route_change_rate, label: "Route fingerprint changes vs baseline churn", weight: 0.60 } - { id: hop_count_z, label: "Hop count deviation", weight: 0.20 } - { id: path_latency_shift, label: "Latency shift on changed paths", weight: 0.20 } routing: signals: - { id: bgp_withdrawals_z, label: "BGP withdrawals/s vs baseline", weight: 0.40 } - { id: bgp_announcements_z, label: "BGP announcements/s vs baseline", weight: 0.25 } - { id: bgp_origin_changes_z, label: "Origin ASN changes vs baseline", weight: 0.20 } - { id: bgp_collector_disagreement, label: "Collector disagreement", weight: 0.15 } corroboration: signals: - { id: vendor_incidents, label: "Public incidents declared by major providers", weight: 1.0 } # Network importance multipliers (target importance 1–5 → weight in aggregations). importance_weights: { 1: 0.4, 2: 0.7, 3: 1.0, 4: 1.5, 5: 2.2 } events: detect_threshold: 45 # component/regional score that opens an event candidate confirm_cycles: 2 # consecutive cycles above threshold before "detected" → "developing" active_cycles: 6 # …before "active" recover_threshold: 30 # below this the event is "recovering" resolve_after_seconds: 600 # continuous time below recover_threshold before "resolved" min_confidence: 0.45 fronts: min_pairs: 3 # source-region → destination-region pairs elevated simultaneously z_threshold: 2.5 min_intensity: 35 scheduler: tiers: { 1: 20, 2: 45, 3: 300, 4: 900 } # seconds between HTTP checks per tier (4 = the long tail: government, media, retail…) dns_every: 600 # 4 resolvers × 2 100 targets: one query per resolver every 10 min per probe ping_every: 120 traceroute_every: 900 boost_factor: 0.5 # during anomalies, intervals are multiplied by this for affected targets boost_seconds: 900 batch_flush_seconds: 10 max_batch: 500 config_refresh_seconds: 300