Split- och depåstatistik är implementerad

This commit is contained in:
larssand
2026-08-25 20:00:55 +02:00
parent 8ea8b3a84e
commit abf887dccd
16 changed files with 564 additions and 46 deletions

View File

@@ -968,7 +968,53 @@ Race data is stored under `resultsBySession[sessionId]`:
The full result object is included in `/api/state` persistence. Only main passings are posted to `/api/passings` and the SQLite passings table. This preserves the existing lap ledger and prevents split/pit records from being interpreted as laps. If split or pit history later needs SQL reporting, add dedicated tables and endpoints rather than inserting those records into `passings`.
### 8.3.3 Managed AMMC process lifecycle
### 8.3.3 Split/pit attribution, analysis, and presentation
`src/decoder_runtime.js` snapshots the active member on `pit_entry` into the competitor record:
```js
{
pitEntryDriverId, pitEntryDriverName,
pitEntryCarId, pitEntryCarName,
pitEntryTransponder
}
```
On `pit_exit`, the resulting `PitStop` uses that entry snapshot rather than the currently active team member. This is essential for endurance races: a team may switch driver, car, or transponder while stopped. `exitTransponder` is stored separately and must not overwrite the entry attribution. After the stop is appended, the snapshot fields are cleared.
Analysis ownership is deliberately split into two pure functions:
| Function | Module | Scope | Consumers |
|---|---|---|---|
| `buildSessionChannelStats(session, deps)` | `src/timing_logic.js` | one heat/session, grouped by competitor key | Timing, Race Setup, team standings, HTML reports, PDF reports |
| `buildDriverTimingChannelStats(state, driverId, classId)` | `src/training_logic.js` | one personal driver profile and selected class across sessions | Training detailed statistics |
`buildSessionChannelStats()` aggregates split count/best/average and pit count/total/best/average, and returns a chronological enriched pit-stop log. `renderSessionChannelAnalysis()` in `src/race_render_helpers.js` is the canonical HTML presentation. Do not independently recalculate these values in Timing or Race Setup.
`buildDriverTimingChannelStats()` resolves every driver record belonging to the same personal profile but applies the selected class filter before reading `resultsBySession`. Consequently multiple transponders in 2WD can be aggregated while 2WD and 4WD data remain separate.
Presentation/data path:
```text
decoder_runtime -> resultsBySession[sessionId].splits/pitStops
-> buildSessionChannelStats
-> renderSessionChannelAnalysis
-> Timing / Race Setup / HTML print
-> buildSessionChannelPdfSections -> PDF export
resultsBySession -> buildDriverTimingChannelStats
-> Training / More statistics
```
Important invariants:
- all displayed pit-stop counts come from completed `pitStops`, never unmatched `pitEvents`
- the pit log is available for every session type, not only `team_race`
- an optional split/pit channel never changes race laps, lap ranking, or finish timing
- old stored pit stops without entry-attribution fields remain readable via competitor fallback labels
- reports must use the same builders as live views to avoid differing totals
### 8.3.4 Managed AMMC process lifecycle
`server.js` owns four process states in `ammcState.channels`: `main`, `split`, `pitEntry`, and `pitExit`. `startAmmcProcesses()` normalizes and validates the complete configuration before spawning one child process per enabled role. All roles use the same resolved AMMC executable and working directory but receive different `-w <port> <decoderHost>` arguments.