Electric Cherry attaches each telemetry report to the newest match on its server and guesses where matches start and end. When a reporter's game_end or game_start is lost or arrives late, finished games are recorded as interrupted and lose their leaderboard credit, and delayed reports can open or close the wrong match.
leaderboard-ingest.ts:65-69 loads the newest match for the server, and every report applies to it.
leaderboard-ingest.ts:82-88 decides that a new match started from a game_start, a changed map, a lower round, or a round report after a completed game. Anything else updates the newest match.
leaderboard-ingest.ts:70-77 only ignores a report identical to the match's last one, so a resent report is safe only if nothing else arrived in between.
leaderboard.md:17 counts only completed matches with a received game_end, and leaderboard.md:154 keeps superseded matches as interrupted. A lost end report and a game that was really cut off look the same.
telemetry.ts:45-101 builds the event from known fields only, so reporters can add fields before Electric Cherry uses them.
api/telemetry/+server.ts:77 already returns the saved report, including the Electric Cherry match id (fleet/telemetry.ts:83).
Recent examples:
#921 (t6_zombie_buried_1, 9 October 05:27 UTC): neither its game_end nor the next game's game_start was processed. The next match, #922, was opened 11.5 s later by a lower-round report with no observed start. #921 was recorded as interrupted, so its five players' rounds 1–9 don't count on the leaderboard.
5 October 17:47:34–38 UTC: delayed reports from four servers were processed within 4 seconds. That produced #660, a 1-second match on t6_zombie_nuked_1 superseded 0.34 s later, and #661, a t5_zombie_sumpf_1 match that started, reached round 3 and completed in 3 seconds.
If every report carries a match key chosen by the game server and a sequence number, Electric Cherry can attach it to the right match, ignore resent reports, and tell a missing end report from an interrupted game. The reporter half (generating the key and sequence, retrying, and resending across map changes) is tracked in josh/tws-zombies-scripts#2.
Fix
Accept an optional match (nonempty string, up to 64 characters) and seq (positive integer) on all four events in parseGameEvent, and keep them on saved telemetry
Store the reporter's match key on the match, unique per server, and record which seq values were applied
Attach a keyed report to the match with that key, creating it if needed and marking the start observed only when its game_start arrives, never to whichever match is newest. Unkeyed reports keep today's rules
Apply each match and seq pair at most once, and never let a report with a lower seq move a match backwards (round, presence or status)
When a new key arrives for a server, close its previous keyed match: completed if that match's game_end was applied, otherwise a distinct "end report missing" result instead of interrupted, shown as such on Matches
Apply a keyed game_end that arrives after a newer match started to its own match, completing it
Record gaps in each match's seq values and expose the number of missing reports in the match API
Document match and seq in the telemetry event table (beta-test-plans.md:60-65) and the keyed match lifecycle in leaderboard.md:152-157
Add tests: a resent report is ignored, a late heartbeat for an old key leaves the newer match alone, a missing game_start still opens the right match, a missing game_end gives "end report missing", a late game_end completes its own match, and unkeyed reports behave as they do today
Electric Cherry attaches each telemetry report to the newest match on its server and guesses where matches start and end. When a reporter's `game_end` or `game_start` is lost or arrives late, finished games are recorded as interrupted and lose their leaderboard credit, and delayed reports can open or close the wrong match.
- `leaderboard-ingest.ts:65-69` loads the newest match for the server, and every report applies to it.
- `leaderboard-ingest.ts:82-88` decides that a new match started from a `game_start`, a changed map, a lower round, or a round report after a completed game. Anything else updates the newest match.
- `leaderboard-ingest.ts:70-77` only ignores a report identical to the match's last one, so a resent report is safe only if nothing else arrived in between.
- `leaderboard.md:17` counts only completed matches with a received `game_end`, and `leaderboard.md:154` keeps superseded matches as interrupted. A lost end report and a game that was really cut off look the same.
- `telemetry.ts:45-101` builds the event from known fields only, so reporters can add fields before Electric Cherry uses them.
- `api/telemetry/+server.ts:77` already returns the saved report, including the Electric Cherry match id (`fleet/telemetry.ts:83`).
Recent examples:
- #921 (`t6_zombie_buried_1`, 9 October 05:27 UTC): neither its `game_end` nor the next game's `game_start` was processed. The next match, #922, was opened 11.5 s later by a lower-round report with no observed start. #921 was recorded as interrupted, so its five players' rounds 1–9 don't count on the leaderboard.
- 5 October 17:47:34–38 UTC: delayed reports from four servers were processed within 4 seconds. That produced #660, a 1-second match on `t6_zombie_nuked_1` superseded 0.34 s later, and #661, a `t5_zombie_sumpf_1` match that started, reached round 3 and completed in 3 seconds.
If every report carries a match key chosen by the game server and a sequence number, Electric Cherry can attach it to the right match, ignore resent reports, and tell a missing end report from an interrupted game. The reporter half (generating the key and sequence, retrying, and resending across map changes) is tracked in [josh/tws-zombies-scripts#2](https://gitea.thewrightserver.net/josh/tws-zombies-scripts/issues/2).
**Fix**
- [x] Accept an optional `match` (nonempty string, up to 64 characters) and `seq` (positive integer) on all four events in `parseGameEvent`, and keep them on saved telemetry
- [x] Store the reporter's match key on the match, unique per server, and record which `seq` values were applied
- [x] Attach a keyed report to the match with that key, creating it if needed and marking the start observed only when its `game_start` arrives, never to whichever match is newest. Unkeyed reports keep today's rules
- [x] Apply each `match` and `seq` pair at most once, and never let a report with a lower `seq` move a match backwards (round, presence or status)
- [x] When a new key arrives for a server, close its previous keyed match: completed if that match's `game_end` was applied, otherwise a distinct "end report missing" result instead of interrupted, shown as such on Matches
- [x] Apply a keyed `game_end` that arrives after a newer match started to its own match, completing it
- [x] Record gaps in each match's `seq` values and expose the number of missing reports in the match API
- [x] Document `match` and `seq` in the telemetry event table (`beta-test-plans.md:60-65`) and the keyed match lifecycle in `leaderboard.md:152-157`
- [x] Add tests: a resent report is ignored, a late heartbeat for an old key leaves the newer match alone, a missing `game_start` still opens the right match, a missing `game_end` gives "end report missing", a late `game_end` completes its own match, and unkeyed reports behave as they do today
Reviewed 785cc4616b. All nine fix items are done, so I'm closing this. Keyed matching takes effect once josh/tws-zombies-scripts#2 sends match and seq. Until then, every report takes the unchanged unkeyed path.
Checklist
Accept match and seq.telemetry.ts:62-68 accepts an optional nonblank match of up to 64 characters and a positive safe-integer seq on all four events, and :109-110 keeps them on the saved report. telemetry.test.ts:62 covers the limits.
Store the key and applied sequences. Migration 18 (leaderboard-reports.ts:11-27) adds reporter_match_key with a unique index per server, last_seq, report_count, and a leaderboard_match_reports table that records each received seq and whether it was applied. leaderboard-report-migration.test.ts covers the upgrade, per-server uniqueness, replaying the migration and removal with retained matches.
Attach by key. Keyed reports go to recordKeyedTelemetry (leaderboard-ingest.ts:73,253), which finds the match by server and key (:258-260) and creates it if needed. createMatch marks the start observed only for a game_start (:142), and observeDelayedStart (:381) records a late one. Unkeyed reports keep the old rules in recordLegacyTelemetry.
Apply each pair once, never backwards. A repeated seq hits ON CONFLICT DO NOTHING and returns without changes (:279-285). A lower seq is stale (:297), and only a stale game_end can still complete its match (:310-316). keyed-telemetry.test.ts:91,115,287 cover a retry across a database reopen, a gap fill and a lower-round report.
End report missing. An unseen key marks the server's active keyed match end-report-missing and an unkeyed one interrupted (:264-270). A match whose game_end was applied is already completed and is left alone. Matches labels and filters the new status (MatchHistory.svelte:203,346), and retention treats it as closed (retention.ts:150).
Late game_end completes its own match.completeDelayedMatch (:338) completes the old match without touching the newer one. Reports for a match that isn't current don't replace the live snapshot or broadcast (fleet/telemetry.ts:36, api/telemetry/+server.ts:66,69). Covered by keyed-telemetry.test.ts:200,339,387.
Record and expose gaps. The match API returns last_seq - report_count as missingReports, or null without sequences (match-history.ts:14-15), and Matches shows "N reports missing" (MatchHistory.svelte:388). Covered by keyed-telemetry.test.ts:239,257 and match-history-query.test.ts:107.
Docs.beta-test-plans.md:76-90 documents both fields and the retry rules, and :208-216 the keyed lifecycle. leaderboard.md:152-166 and :378-379 cover the new status and the API fields.
Tests. All six cases are in keyed-telemetry.test.ts: a resent report (:91), a late old-key heartbeat and a missing game_start (:140), and a missing and a late game_end (:200). The unkeyed tests in telemetry.test.ts and the leaderboard suites pass with their assertions unchanged.
Review notes
Good extra catches: retries and old keys are still acknowledged with their own match id but don't broadcast (keyed-telemetry.test.ts:387), and ending player counts for keyed matches use presence in the final report rather than the last report applied (match-history.ts).
The 8 test files the commit touched pass locally (147 tests), as do 22 related leaderboard, match, player, metrics and telemetry files (406 tests). npm run check reports 0 errors and 0 warnings.
Minor and non-blocking: any unseen key supersedes the live game, so a delayed first report from an older game still closes the newer one. In a scratch test (not committed), game new reached round 4, then a late first report for old arrived. That marked new End report missing and made old the server's live telemetry. new's later heartbeats then stopped updating the live view, because result.current (:326) only holds for the newest match, which is now old. When old's late report was a heartbeat, old also stayed active after new ended. This needs a game's first processed report to arrive out of order, which the head-of-queue retries in josh/tws-zombies-scripts#2 make unlikely. Ruling it out would need the reporter to send something Electric Cherry can order, such as a per-server game counter.
Reviewed 785cc4616b06c19c1a76c4a56ee1495a842dba72. All nine fix items are done, so I'm closing this. Keyed matching takes effect once josh/tws-zombies-scripts#2 sends `match` and `seq`. Until then, every report takes the unchanged unkeyed path.
**Checklist**
- [x] **Accept `match` and `seq`.** `telemetry.ts:62-68` accepts an optional nonblank `match` of up to 64 characters and a positive safe-integer `seq` on all four events, and `:109-110` keeps them on the saved report. `telemetry.test.ts:62` covers the limits.
- [x] **Store the key and applied sequences.** Migration 18 (`leaderboard-reports.ts:11-27`) adds `reporter_match_key` with a unique index per server, `last_seq`, `report_count`, and a `leaderboard_match_reports` table that records each received `seq` and whether it was applied. `leaderboard-report-migration.test.ts` covers the upgrade, per-server uniqueness, replaying the migration and removal with retained matches.
- [x] **Attach by key.** Keyed reports go to `recordKeyedTelemetry` (`leaderboard-ingest.ts:73,253`), which finds the match by server and key (`:258-260`) and creates it if needed. `createMatch` marks the start observed only for a `game_start` (`:142`), and `observeDelayedStart` (`:381`) records a late one. Unkeyed reports keep the old rules in `recordLegacyTelemetry`.
- [x] **Apply each pair once, never backwards.** A repeated `seq` hits `ON CONFLICT DO NOTHING` and returns without changes (`:279-285`). A lower `seq` is stale (`:297`), and only a stale `game_end` can still complete its match (`:310-316`). `keyed-telemetry.test.ts:91,115,287` cover a retry across a database reopen, a gap fill and a lower-round report.
- [x] **End report missing.** An unseen key marks the server's active keyed match `end-report-missing` and an unkeyed one `interrupted` (`:264-270`). A match whose `game_end` was applied is already `completed` and is left alone. Matches labels and filters the new status (`MatchHistory.svelte:203,346`), and retention treats it as closed (`retention.ts:150`).
- [x] **Late `game_end` completes its own match.** `completeDelayedMatch` (`:338`) completes the old match without touching the newer one. Reports for a match that isn't current don't replace the live snapshot or broadcast (`fleet/telemetry.ts:36`, `api/telemetry/+server.ts:66,69`). Covered by `keyed-telemetry.test.ts:200,339,387`.
- [x] **Record and expose gaps.** The match API returns `last_seq - report_count` as `missingReports`, or null without sequences (`match-history.ts:14-15`), and Matches shows "N reports missing" (`MatchHistory.svelte:388`). Covered by `keyed-telemetry.test.ts:239,257` and `match-history-query.test.ts:107`.
- [x] **Docs.** `beta-test-plans.md:76-90` documents both fields and the retry rules, and `:208-216` the keyed lifecycle. `leaderboard.md:152-166` and `:378-379` cover the new status and the API fields.
- [x] **Tests.** All six cases are in `keyed-telemetry.test.ts`: a resent report (`:91`), a late old-key heartbeat and a missing `game_start` (`:140`), and a missing and a late `game_end` (`:200`). The unkeyed tests in `telemetry.test.ts` and the leaderboard suites pass with their assertions unchanged.
**Review notes**
- Good extra catches: retries and old keys are still acknowledged with their own match id but don't broadcast (`keyed-telemetry.test.ts:387`), and ending player counts for keyed matches use presence in the final report rather than the last report applied (`match-history.ts`).
- The 8 test files the commit touched pass locally (147 tests), as do 22 related leaderboard, match, player, metrics and telemetry files (406 tests). `npm run check` reports 0 errors and 0 warnings.
- Minor and non-blocking: any unseen key supersedes the live game, so a delayed *first* report from an older game still closes the newer one. In a scratch test (not committed), game `new` reached round 4, then a late first report for `old` arrived. That marked `new` End report missing and made `old` the server's live telemetry. `new`'s later heartbeats then stopped updating the live view, because `result.current` (`:326`) only holds for the newest match, which is now `old`. When `old`'s late report was a heartbeat, `old` also stayed active after `new` ended. This needs a game's first processed report to arrive out of order, which the head-of-queue retries in josh/tws-zombies-scripts#2 make unlikely. Ruling it out would need the reporter to send something Electric Cherry can order, such as a per-server game counter.
Reviewed 785cc4616b and the follow-up 76325b99ad against current main 2f52dcb1ef. The follow-up accurately documents the first-report ordering limitation identified in the previous review; all nine fix items remain satisfied, so this stays closed.
Checklist
Accept and retain reporter metadata.src/lib/telemetry.ts:65-70,116-117 validates and retains optional match and seq; telemetry parsing and route tests cover supported events and limits.
Persist keys and received sequences.src/lib/server/db/leaderboard-reports.ts retains the per-server key constraint and durable sequence receipts, with migration/replay/retention coverage.
Attach reports by key.leaderboard-ingest.ts:267 resolves the supplied server/key pair. Missing and delayed starts are covered; recordLegacyTelemetry preserves unkeyed behavior.
Deduplicate and prevent backwards updates. Sequence conflicts return without applying a report, and lower sequences cannot rewind the current roster or counters. Keyed telemetry tests cover intervening reports and database reopen.
Distinguish missing ends. An unseen key marks active keyed history End report missing (leaderboard-ingest.ts:281). Match History labels/filters it and exposes missing-report counts.
Apply delayed endings to their own match. Late known-key endings complete that match; fleet/telemetry.ts:36 and api/telemetry/+server.ts:66-69 prevent old reports from replacing or broadcasting the live snapshot.
Expose sequence gaps.fleet/match-history.ts:14-15 returns the key and known missing-report count. Tests verify gap filling and duplicate handling.
Document protocol and boundaries.docs/guides/leaderboard.md:183-209 and beta-test-plans.md:208-228 now distinguish known older keys from previously unseen keys. They explain first-processed-report ordering, why per-match sequences cannot order games, preserving delivery order across games, and the additional metadata a stronger protocol would need. The cross-reference resolves to the existing persistence section.
Cover the requested cases. The current full suite includes keyed/unkeyed telemetry, report migration, match-history queries, retention, and match UI coverage. VITEST_MAX_WORKERS=2 npm test passed all 3,055 tests in 227 files, including client UI, score ingestion, score/report migrations, match detail, and migration-memory coverage. npm run check passed with zero errors and zero warnings.
Review notes
The follow-up changes documentation only. The limitation is documented, not eliminated: the first report for a previously unseen older game can still supersede the current live game. This remains the non-blocking limitation recorded in the prior review.
Reviewed and tested current main at 2f52dcb; no application source changes were made during review.
Reviewed 785cc4616b06c19c1a76c4a56ee1495a842dba72 and the follow-up 76325b99adefcfe953ead943497fdff074852bdb against current main 2f52dcb1ef444b2c0a0e0684afea5a9ed269ed1b. The follow-up accurately documents the first-report ordering limitation identified in the previous review; all nine fix items remain satisfied, so this stays closed.
**Checklist**
- [x] **Accept and retain reporter metadata.** `src/lib/telemetry.ts:65-70,116-117` validates and retains optional `match` and `seq`; telemetry parsing and route tests cover supported events and limits.
- [x] **Persist keys and received sequences.** `src/lib/server/db/leaderboard-reports.ts` retains the per-server key constraint and durable sequence receipts, with migration/replay/retention coverage.
- [x] **Attach reports by key.** `leaderboard-ingest.ts:267` resolves the supplied server/key pair. Missing and delayed starts are covered; `recordLegacyTelemetry` preserves unkeyed behavior.
- [x] **Deduplicate and prevent backwards updates.** Sequence conflicts return without applying a report, and lower sequences cannot rewind the current roster or counters. Keyed telemetry tests cover intervening reports and database reopen.
- [x] **Distinguish missing ends.** An unseen key marks active keyed history End report missing (`leaderboard-ingest.ts:281`). Match History labels/filters it and exposes missing-report counts.
- [x] **Apply delayed endings to their own match.** Late known-key endings complete that match; `fleet/telemetry.ts:36` and `api/telemetry/+server.ts:66-69` prevent old reports from replacing or broadcasting the live snapshot.
- [x] **Expose sequence gaps.** `fleet/match-history.ts:14-15` returns the key and known missing-report count. Tests verify gap filling and duplicate handling.
- [x] **Document protocol and boundaries.** `docs/guides/leaderboard.md:183-209` and `beta-test-plans.md:208-228` now distinguish known older keys from previously unseen keys. They explain first-processed-report ordering, why per-match sequences cannot order games, preserving delivery order across games, and the additional metadata a stronger protocol would need. The cross-reference resolves to the existing persistence section.
- [x] **Cover the requested cases.** The current full suite includes keyed/unkeyed telemetry, report migration, match-history queries, retention, and match UI coverage. `VITEST_MAX_WORKERS=2 npm test` passed all 3,055 tests in 227 files, including client UI, score ingestion, score/report migrations, match detail, and migration-memory coverage. `npm run check` passed with zero errors and zero warnings.
**Review notes**
- The follow-up changes documentation only. The limitation is documented, not eliminated: the first report for a previously unseen older game can still supersede the current live game. This remains the non-blocking limitation recorded in the prior review.
- Reviewed and tested current main at `2f52dcb`; no application source changes were made during review.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Electric Cherry attaches each telemetry report to the newest match on its server and guesses where matches start and end. When a reporter's
game_endorgame_startis lost or arrives late, finished games are recorded as interrupted and lose their leaderboard credit, and delayed reports can open or close the wrong match.leaderboard-ingest.ts:65-69loads the newest match for the server, and every report applies to it.leaderboard-ingest.ts:82-88decides that a new match started from agame_start, a changed map, a lower round, or a round report after a completed game. Anything else updates the newest match.leaderboard-ingest.ts:70-77only ignores a report identical to the match's last one, so a resent report is safe only if nothing else arrived in between.leaderboard.md:17counts only completed matches with a receivedgame_end, andleaderboard.md:154keeps superseded matches as interrupted. A lost end report and a game that was really cut off look the same.telemetry.ts:45-101builds the event from known fields only, so reporters can add fields before Electric Cherry uses them.api/telemetry/+server.ts:77already returns the saved report, including the Electric Cherry match id (fleet/telemetry.ts:83).Recent examples:
t6_zombie_buried_1, 9 October 05:27 UTC): neither itsgame_endnor the next game'sgame_startwas processed. The next match, #922, was opened 11.5 s later by a lower-round report with no observed start. #921 was recorded as interrupted, so its five players' rounds 1–9 don't count on the leaderboard.t6_zombie_nuked_1superseded 0.34 s later, and #661, at5_zombie_sumpf_1match that started, reached round 3 and completed in 3 seconds.If every report carries a match key chosen by the game server and a sequence number, Electric Cherry can attach it to the right match, ignore resent reports, and tell a missing end report from an interrupted game. The reporter half (generating the key and sequence, retrying, and resending across map changes) is tracked in josh/tws-zombies-scripts#2.
Fix
match(nonempty string, up to 64 characters) andseq(positive integer) on all four events inparseGameEvent, and keep them on saved telemetryseqvalues were appliedgame_startarrives, never to whichever match is newest. Unkeyed reports keep today's rulesmatchandseqpair at most once, and never let a report with a lowerseqmove a match backwards (round, presence or status)game_endwas applied, otherwise a distinct "end report missing" result instead of interrupted, shown as such on Matchesgame_endthat arrives after a newer match started to its own match, completing itseqvalues and expose the number of missing reports in the match APImatchandseqin the telemetry event table (beta-test-plans.md:60-65) and the keyed match lifecycle inleaderboard.md:152-157game_startstill opens the right match, a missinggame_endgives "end report missing", a lategame_endcompletes its own match, and unkeyed reports behave as they do todayReviewed
785cc4616b. All nine fix items are done, so I'm closing this. Keyed matching takes effect once josh/tws-zombies-scripts#2 sendsmatchandseq. Until then, every report takes the unchanged unkeyed path.Checklist
matchandseq.telemetry.ts:62-68accepts an optional nonblankmatchof up to 64 characters and a positive safe-integerseqon all four events, and:109-110keeps them on the saved report.telemetry.test.ts:62covers the limits.leaderboard-reports.ts:11-27) addsreporter_match_keywith a unique index per server,last_seq,report_count, and aleaderboard_match_reportstable that records each receivedseqand whether it was applied.leaderboard-report-migration.test.tscovers the upgrade, per-server uniqueness, replaying the migration and removal with retained matches.recordKeyedTelemetry(leaderboard-ingest.ts:73,253), which finds the match by server and key (:258-260) and creates it if needed.createMatchmarks the start observed only for agame_start(:142), andobserveDelayedStart(:381) records a late one. Unkeyed reports keep the old rules inrecordLegacyTelemetry.seqhitsON CONFLICT DO NOTHINGand returns without changes (:279-285). A lowerseqis stale (:297), and only a stalegame_endcan still complete its match (:310-316).keyed-telemetry.test.ts:91,115,287cover a retry across a database reopen, a gap fill and a lower-round report.end-report-missingand an unkeyed oneinterrupted(:264-270). A match whosegame_endwas applied is alreadycompletedand is left alone. Matches labels and filters the new status (MatchHistory.svelte:203,346), and retention treats it as closed (retention.ts:150).game_endcompletes its own match.completeDelayedMatch(:338) completes the old match without touching the newer one. Reports for a match that isn't current don't replace the live snapshot or broadcast (fleet/telemetry.ts:36,api/telemetry/+server.ts:66,69). Covered bykeyed-telemetry.test.ts:200,339,387.last_seq - report_countasmissingReports, or null without sequences (match-history.ts:14-15), and Matches shows "N reports missing" (MatchHistory.svelte:388). Covered bykeyed-telemetry.test.ts:239,257andmatch-history-query.test.ts:107.beta-test-plans.md:76-90documents both fields and the retry rules, and:208-216the keyed lifecycle.leaderboard.md:152-166and:378-379cover the new status and the API fields.keyed-telemetry.test.ts: a resent report (:91), a late old-key heartbeat and a missinggame_start(:140), and a missing and a lategame_end(:200). The unkeyed tests intelemetry.test.tsand the leaderboard suites pass with their assertions unchanged.Review notes
keyed-telemetry.test.ts:387), and ending player counts for keyed matches use presence in the final report rather than the last report applied (match-history.ts).npm run checkreports 0 errors and 0 warnings.newreached round 4, then a late first report foroldarrived. That markednewEnd report missing and madeoldthe server's live telemetry.new's later heartbeats then stopped updating the live view, becauseresult.current(:326) only holds for the newest match, which is nowold. Whenold's late report was a heartbeat,oldalso stayed active afternewended. This needs a game's first processed report to arrive out of order, which the head-of-queue retries in josh/tws-zombies-scripts#2 make unlikely. Ruling it out would need the reporter to send something Electric Cherry can order, such as a per-server game counter.Reviewed
785cc4616band the follow-up76325b99adagainst current main2f52dcb1ef. The follow-up accurately documents the first-report ordering limitation identified in the previous review; all nine fix items remain satisfied, so this stays closed.Checklist
src/lib/telemetry.ts:65-70,116-117validates and retains optionalmatchandseq; telemetry parsing and route tests cover supported events and limits.src/lib/server/db/leaderboard-reports.tsretains the per-server key constraint and durable sequence receipts, with migration/replay/retention coverage.leaderboard-ingest.ts:267resolves the supplied server/key pair. Missing and delayed starts are covered;recordLegacyTelemetrypreserves unkeyed behavior.leaderboard-ingest.ts:281). Match History labels/filters it and exposes missing-report counts.fleet/telemetry.ts:36andapi/telemetry/+server.ts:66-69prevent old reports from replacing or broadcasting the live snapshot.fleet/match-history.ts:14-15returns the key and known missing-report count. Tests verify gap filling and duplicate handling.docs/guides/leaderboard.md:183-209andbeta-test-plans.md:208-228now distinguish known older keys from previously unseen keys. They explain first-processed-report ordering, why per-match sequences cannot order games, preserving delivery order across games, and the additional metadata a stronger protocol would need. The cross-reference resolves to the existing persistence section.VITEST_MAX_WORKERS=2 npm testpassed all 3,055 tests in 227 files, including client UI, score ingestion, score/report migrations, match detail, and migration-memory coverage.npm run checkpassed with zero errors and zero warnings.Review notes
2f52dcb; no application source changes were made during review.