Commit Graph
4 Commits
Author SHA1 Message Date
dborup 2f044a6a00 feat: add "This Week's Best" rolling-7-day records to Ping Scores
The all-time records lock in forever once someone sets a big one (e.g.
a 364km farthest ping) -- ThisWeek mirrors the same 5 slots on a
rolling 7-day window so there's an achievable target to chase
regularly, shown alongside (not instead of) the all-time board.
2026-07-28 13:56:47 +02:00
dborup 640c552181 fix: scope Top Senders leaderboard to a rolling 30-day window
Unlike the all-time records and the Top Relays/Top First-Hearers boards,
"who pings the most" is more meaningful as an ongoing thing than a
fixed leaderboard someone can win once and hold forever.
2026-07-28 13:37:32 +02:00
dborupandClaude Sonnet 5 5180181083 feat: add Top Senders leaderboard to Ping Scores page
dborup asked for suggestions on what else to add to Ping Scores; picked
"Top Senders" from the shortlist -- the page had Top Relays and Top
First-Hearers but nothing ranking who actually sends the most pings.

Backend: new SenderLeaderboard field on PingScoresSnapshot, tallied
alongside the existing relay/observer leaderboards in
computeAllPingScores. Keyed by the sender display name straight from
the channel message (ping_triggers.sender) -- unlike relays/observers
there's no resolved pubkey to link back to a node, so entries
deliberately never carry one (PingLeaderboardEntry.Pubkey stays
omitted).

Frontend: leaderboardTableHtml gained an optional column-label param
("Sender" instead of the default "Node") since sender entries aren't
resolvable mesh nodes and "Node" would be misleading there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 13:23:53 +02:00
dborupandClaude Sonnet 5 e9f5b13b70 feat: Ping Scores — global highscore board and leaderboards
New feature: every "ping" channel message gets recorded and scored,
producing records (farthest reach, most hops, widest simultaneous
spread, fastest full spread, most airtime-efficient) plus leaderboards
(top relay nodes, top first-hearer observers). Global, not scoped by
region/area, per dborup's request.

Architecture:
- Ingestor writes a lightweight ping_triggers row (tx_id, hash,
  channel_hash, sender, first_seen) at ingest time when a new CHAN
  transmission matches the same isPingTrigger logic the pong-reply
  feature already uses (mirrored, kept in sync by hand -- now a 3rd
  copy alongside public/channels.js and cmd/server/db.go).
- Server periodically (every 2 min) joins ping_triggers with the same
  GetPacketPath + LoRa-airtime-estimate logic behind View Path,
  computing the full snapshot in memory (no write access needed from
  the read-only server) and caching it, matching the steady-state
  recomputer pattern used throughout cmd/server.
- New GET /api/ping-scores endpoint + Ping Scores page (linked from
  Tools and from every pong reply bubble in Channels).

Schema change follows the dbschema.go INVARIANT from #1321 exactly:
migration in Apply() (ingestor-only), assertion in AssertReady()
(server fatal-exits if ping_triggers is missing rather than silently
degrading) -- the same pattern #1865/#1867's configured_scope should
have used but didn't fully wire up (see the ping_scores.go doc
comment and today's earlier startup-race fix for the story).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 15:01:21 +02:00