feat(practice): flag suspiciously short laps and remove any lap in one click

Practice laps under 85% of the driver's own median (a likely shortcut)
are flagged: counted, but never a best lap, record or training stat
until approved. Timing and Race Day get a one-click Approve/Remove
panel, overlays show a warning mark, and any lap can be removed or
restored from Timing and Judging with undo.

Also sends judge corrections straight to the server so its hot-results
protection can no longer hold back a correction made right after a
passing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
larssand
2026-10-07 19:53:23 +02:00
parent 3cc4fa0845
commit 8601954ea2
24 changed files with 556 additions and 60 deletions

View File

@@ -388,6 +388,17 @@ test("a stale full-state save from a second browser cannot revert a session's ju
// ...but the live race result survived the stale overwrite instead of reverting to empty.
assert.deepEqual(afterStaleSave.state.resultsBySession.session_1, liveSessionResult);
// A judge removing that lap moments later must not be held back by the same protection:
// the corrected result goes through /api/session-results and wins straight away.
const correctedResult = {
...liveSessionResult,
competitors: { driver_1: { ...liveSessionResult.competitors.driver_1, laps: 0, bestLapMs: null } },
passings: [{ ...liveSessionResult.passings[0], validLap: false, invalidReason: "manual_invalid" }],
};
assert.equal((await fetch(`${baseUrl}/api/session-results`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sessionId: "session_1", sessionResult: correctedResult }) })).status, 200);
assert.deepEqual((await (await fetch(`${baseUrl}/api/state`)).json()).state.resultsBySession.session_1, correctedResult);
assert.equal((await fetch(`${baseUrl}/api/session-results`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sessionId: "session_1" }) })).status, 400);
// The protection is time-bounded, not permanent: once the window passes, a save is trusted
// again, so a legitimate later change to that same session's results (e.g. an admin
// deleting the session) still takes effect.