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:
@@ -157,6 +157,33 @@ test("personal best is per session and track layout - not per stint, and an old
|
||||
assert.equal(harness.state.resultsBySession.session_1.passings.at(-1).trackLayoutId, "layout_b", "each lap remembers its layout");
|
||||
});
|
||||
|
||||
test("practice: a shortcut lap is flagged suspect - counted, but no best lap, personal best or record", () => {
|
||||
const harness = createHarness({ sessionType: "open_practice" });
|
||||
const entry = () => Object.values(harness.state.resultsBySession.session_1.competitors)[0];
|
||||
let ts = 1_000;
|
||||
[20_000, 20_400, 19_800, 20_200, 20_600, 20_100].forEach((lapMs) => { ts += lapMs; harness.passing(ts, "main"); });
|
||||
assert.equal(entry().bestLapMs, 19_800);
|
||||
const pbsBefore = harness.audioEvents.filter((event) => event === "personal_best").length;
|
||||
ts += 15_000; // usually ~20 s, then one lap of 15 s: cut across the track
|
||||
harness.passing(ts, "main");
|
||||
const last = harness.state.resultsBySession.session_1.passings.at(-1);
|
||||
assert.equal(last.suspect, true);
|
||||
assert.equal(entry().laps, 7, "still counted as a lap");
|
||||
assert.equal(entry().bestLapMs, 19_800, "not a best lap");
|
||||
assert.equal(harness.audioEvents.filter((event) => event === "personal_best").length, pbsBefore, "no personal best call for it");
|
||||
ts += 15_100; // a second shortcut in a row is flagged too (suspect laps aren't the reference)
|
||||
harness.passing(ts, "main");
|
||||
assert.equal(harness.state.resultsBySession.session_1.passings.at(-1).suspect, true);
|
||||
assert.ok(harness.overlayEvents.some((event) => event.type === "suspect"), "the overlay event feed shows it");
|
||||
});
|
||||
|
||||
test("races never flag suspect laps - that's what the minimum lap time is for", () => {
|
||||
const harness = createHarness({ sessionType: "heat" });
|
||||
let ts = 1_000;
|
||||
[20_000, 20_400, 19_800, 20_200, 20_600, 12_000].forEach((lapMs) => { ts += lapMs; harness.passing(ts, "main"); });
|
||||
assert.equal(harness.state.resultsBySession.session_1.passings.some((passing) => passing.suspect), false);
|
||||
});
|
||||
|
||||
test("pit entry and exit create one timed stop without adding laps", () => {
|
||||
const harness = createHarness();
|
||||
harness.passing(17_000, "main");
|
||||
|
||||
Reference in New Issue
Block a user