Until now there was no way to find a completed session without already
knowing which event it belonged to - navigation was strictly Events ->
one event -> its sessions. A new "Resultatarkiv" view lists every
finished session across all events, searchable by event/session name,
class, driver and date range.
Opening a session reuses the existing single-session leaderboard
builder for standings and the existing per-competitor lap lookup for
lap history - no new results logic - plus a session-wide penalties/
corrections list (resultsBySession[id].adjustments), previously only
visible in the live judging action log. Export buttons reuse the
existing per-event PDF and race-package JSON export functions rather
than adding a new format.
Investigated what should happen to raw timing data when a race is
deleted. Training statistics and session replay already read from
their own independent, deliberately-retained copies that survive
deletion by existing design - unaffected either way. The one thing
that outlived deletion with no purpose was the raw `passings` SQLite
rows (write-only; nothing in the app reads them), growing forever with
driver IDs never purged. A new POST /api/passings/purge endpoint now
removes exactly the deleted session(s)' rows, called as a best-effort
side call from both delete-event and delete-session.
Also fixes a real bug found while building this: ensureSessionResult
guarded adjustments/splits/pitEvents/pitStops against being missing on
an already-existing result, but not passings itself, so viewing lap
history for such a result (e.g. an older/imported race package)
crashed outright.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Investigated whether two admin browsers open at once can overwrite each
other's changes, per an explicit request to report the risk before
making bigger changes. Found that POST /api/state always replaces the
entire stored document with a client's in-memory copy, with no version
check and no per-field merge - and a browser only ever pushes, never
re-fetching server state after page load except on the Overlay view.
An idle browser's next save, even an unrelated edit, could silently
revert another browser's more recent changes, worst case a live race's
in-progress results.
Two scoped fixes instead of the bigger optimistic-locking rework (that
needs real UX decisions about conflicting saves, deferred separately):
1. server.js now remembers which session results were just written by
a real live decoder passing (/api/passings) and protects that key
for 15 seconds against being reverted by a stale full-state save,
while still applying the rest of that save normally.
2. Every non-Overlay view now quietly refreshes its data in the
background every 15 seconds (skipped while a local edit is
pending), without ever calling renderView(), so it can never
discard an open, unsaved edit form - shrinking how stale a
browser's next save can be from hours to seconds.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>