Fix lap limits and five-minute stint statistics

This commit is contained in:
larssand
2026-09-02 19:36:25 +02:00
parent f561dd8feb
commit 483a9dbd5a
14 changed files with 356 additions and 110 deletions

View File

@@ -88,7 +88,7 @@ test("ledger sync retains archived laps and rebuilds current session laps", () =
resultsBySession: {
live: {
passings: [
{ driverId: "driver_1", competitorKey: "driver_1", lapMs: 16500, timestamp: 3000, validLap: true },
{ driverId: "driver_1", competitorKey: "driver_1", lapMs: 16500, timestamp: 3000, validLap: true, validationWarning: "above_max_stint", excludedFromPace: true, stintBoundary: true },
{ driverId: "driver_1", competitorKey: "driver_1", lapMs: 9000, timestamp: 4000, validLap: false },
{ driverId: "", competitorKey: "anonymous", lapMs: 17000, timestamp: 5000, validLap: true },
{ driverId: "driver_1", competitorKey: "driver_1", lapMs: 500, timestamp: 6000, validLap: true },
@@ -106,6 +106,8 @@ test("ledger sync retains archived laps and rebuilds current session laps", () =
assert.equal(liveLap.lapMs, 16500);
assert.equal(liveLap.sessionName, "Free Practice");
assert.equal(liveLap.eventName, "Club practice");
assert.equal(liveLap.excludedFromPace, true);
assert.equal(liveLap.stintBoundary, true);
assert.equal(synced.goals.length, 1);
assert.equal(synced.shares.length, 1);
assert.equal(synced.markers.length, 1);
@@ -137,6 +139,24 @@ test("driver statistics remain isolated and aggregate days and sessions", () =>
assert.equal(stats.dailySummaries[1].laps, 2);
});
test("counted stint-boundary laps do not distort driver pace averages", () => {
const state = {
training: {
ledger: [
{ driverId: "driver_1", sourceId: "tp_1", sessionId: "practice", timestamp: 37_000, lapMs: 37_000 },
{ driverId: "driver_1", sourceId: "tp_1", sessionId: "practice", timestamp: 74_000, lapMs: 37_000 },
{ driverId: "driver_1", sourceId: "tp_1", sessionId: "practice", timestamp: 164_000, lapMs: 90_000, excludedFromPace: true, stintBoundary: true },
],
},
};
const stats = buildDriverTrainingStats(state, "driver_1");
assert.equal(stats.totalLaps, 3);
assert.equal(stats.bestLapMs, 37_000);
assert.equal(stats.averageLapMs, 37_000);
assert.equal(stats.stintCount, 2);
});
test("split and pit statistics aggregate by personal profile and selected class", () => {
const state = {
drivers: [
@@ -294,9 +314,25 @@ test("training stints split after a break over two minutes or a session change",
assert.equal(stints[0].laps.length, 2);
assert.equal(stints[1].laps.length, 1);
assert.equal(stints[1].laps[0].excludedFromPace, true);
assert.equal(stints[1].durationMs, 0);
assert.equal(stints[1].startedAt, 200_001);
assert.equal(stints[2].sessionId, "practice_2");
});
test("configured maximum lap time creates a new pace stint below the fallback break", () => {
const stints = splitTrainingStints([
{ sessionId: "practice_1", sourceId: "tp_1", timestamp: 37_000, lapMs: 37_000 },
{ sessionId: "practice_1", sourceId: "tp_1", timestamp: 74_000, lapMs: 37_000 },
{ sessionId: "practice_1", sourceId: "tp_1", timestamp: 164_000, lapMs: 90_000, excludedFromPace: true, stintBoundary: true },
{ sessionId: "practice_1", sourceId: "tp_1", timestamp: 201_000, lapMs: 37_000 },
]);
assert.equal(stints.length, 2);
assert.equal(stints[1].startedAt, 164_000);
assert.equal(stints[1].durationMs, 37_000);
assert.equal(stints[1].laps.filter((lap) => !lap.excludedFromPace).length, 1);
});
test("best consecutive laps never cross a stint boundary", () => {
const stints = splitTrainingStints([
{ sessionId: "practice_1", timestamp: 18_000, lapMs: 18_000 },
@@ -328,6 +364,25 @@ test("best five-minute result counts a final lap started before the cutoff and r
assert.equal(result.endedAt, 314_123);
});
test("best five-minute result never combines simultaneous transponder sources", () => {
const laps = ["transponder_a", "transponder_b"].flatMap((sourceId) => (
Array.from({ length: 9 }, (_, index) => ({
driverId: sourceId,
sourceId,
sessionId: "practice_1",
timestamp: (index + 1) * 37_000,
lapMs: 37_000,
}))
));
const stints = splitTrainingStints(laps);
const result = getBestTrainingDurationResult(stints, 300_000);
assert.equal(stints.length, 2);
assert.equal(result.lapCount, 9);
assert.equal(result.totalMs, 333_000);
assert.ok(result.totalMs <= result.targetMs + 37_000);
});
test("a stint shorter than the target duration has no five-minute result", () => {
const stints = splitTrainingStints([
{ sessionId: "practice_1", timestamp: 18_000, lapMs: 18_000 },