declarative relay deployment on hetzner relay-eval.waow.tech
atproto relay
14
fork

Configure Feed

Select the types of activity you want to include in your feed.

relay-eval dashboard: add outlier detection for event count spikes

flag relays with >1.5x median event count with a warning icon and
explanation. catches replay-after-restart scenarios where one relay
reports significantly more events than peers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+20 -1
+20 -1
relay-eval/src/static/index.html
··· 71 71 .c-gap { color: var(--red); } 72 72 .c-unr { color: var(--yellow); } 73 73 .c-dead { color: var(--muted); } 74 + .outlier { font-size: 0.7rem; color: var(--yellow); margin-left: 0.4rem; } 75 + .outlier-note { color: var(--yellow); font-size: 0.8rem; margin-top: 0.5rem; line-height: 1.5; } 74 76 75 77 /* expandable */ 76 78 .xrow { cursor: pointer; user-select: none; } ··· 226 228 rd[d.relay].dids.push(d); 227 229 } 228 230 231 + // outlier detection: flag relays with event counts >1.5x the median 232 + const active = data.stats.filter(s => s.events > 0).map(s => s.events).sort((a, b) => a - b); 233 + const median = active.length > 0 ? active[Math.floor(active.length / 2)] : 0; 234 + const outliers = new Set(); 235 + if (median > 0) { 236 + for (const s of data.stats) { 237 + if (s.events > median * 1.5) outliers.add(s.host); 238 + } 239 + } 240 + 229 241 // coverage table 230 242 h += `<p class="sec">coverage</p>`; 231 243 h += `<p class="sec-desc">each relay independently discovers PDS hosts. coverage = accounts this relay saw / accounts any relay saw.</p>`; ··· 243 255 const byLink = o.url 244 256 ? `<a href="${o.url}" target="_blank">${o.name}</a>` 245 257 : o.name; 258 + const isOutlier = outliers.has(s.host); 259 + const pctAbove = isOutlier ? Math.round((s.events / median - 1) * 100) : 0; 246 260 h += `<tr${s.events === 0 ? ' class="dimmed"' : ''}>`; 247 261 h += `<td>${rn(s.host)}</td>`; 248 262 h += `<td class="run-by">${byLink}</td>`; 249 - h += `<td class="num">${s.events.toLocaleString()}</td>`; 263 + h += `<td class="num">${s.events.toLocaleString()}${isOutlier ? `<span class="outlier" title="${pctAbove}% above median \u2014 likely replaying backlog after a restart">\u26a0</span>` : ''}</td>`; 250 264 h += `<td class="num">${s.unique_dids.toLocaleString()}</td>`; 251 265 h += `<td class="num">${pct(s.unique_dids, union)}</td>`; 252 266 h += `<td class="num">${missed > 0 ? missed.toLocaleString() : '\u2014'}</td>`; ··· 255 269 } 256 270 } 257 271 h += `</tbody></table>`; 272 + 273 + if (outliers.size > 0) { 274 + const names = [...outliers].map(host => rn(host)).join(', '); 275 + h += `<p class="outlier-note">\u26a0 ${names} reported significantly more events than other relays during this window \u2014 likely replaying buffered events after a restart.</p>`; 276 + } 258 277 259 278 // breakdown 260 279 const withMisses = data.stats.filter(s => {