Add persistent driver training history and progression
This commit is contained in:
@@ -399,16 +399,21 @@ Type:
|
||||
|
||||
Owns:
|
||||
- training-state normalization
|
||||
- valid driver-lap aggregation across `resultsBySession`
|
||||
- lifetime/session/best-lap/consistency calculations
|
||||
- durable ledger synchronization from `resultsBySession`
|
||||
- valid driver-lap aggregation across the training ledger
|
||||
- lifetime/session/day/best-lap/average/consistency calculations
|
||||
- daily summaries, controlled-lap streak, and recent personal-best gain
|
||||
- rule-based practice recommendation selection
|
||||
- milestone progress calculation
|
||||
- automatic and custom milestone progress calculation
|
||||
|
||||
Rules:
|
||||
- only passings with a matching `driverId` are included
|
||||
- invalid laps and lap times at or below `500 ms` are excluded
|
||||
- anonymous Open Practice transponders are excluded until registered as drivers
|
||||
- consistency is the P10-to-P90 spread of the latest 30 valid laps divided by their mean
|
||||
- every save replaces ledger rows only for session IDs that still exist in `resultsBySession`
|
||||
- ledger rows for a deleted session are retained and become historical records
|
||||
- `sourceKey` deduplicates repeated saves of the same session passing
|
||||
|
||||
### `src/training_views.js`
|
||||
Type:
|
||||
@@ -417,6 +422,7 @@ Type:
|
||||
Owns:
|
||||
- driver selector
|
||||
- training stat cards and recommendation display
|
||||
- automatic next-level card and daily practice history
|
||||
- milestone/reward create, claim, and delete actions
|
||||
- mobile-responsive training markup
|
||||
|
||||
@@ -1435,7 +1441,8 @@ This bucket is the most dynamic part of state and is mutated heavily during live
|
||||
|
||||
```js
|
||||
{
|
||||
goals: TrainingGoal[]
|
||||
goals: TrainingGoal[],
|
||||
ledger: TrainingLap[]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1453,20 +1460,40 @@ This bucket is the most dynamic part of state and is mutated heavily during live
|
||||
}
|
||||
```
|
||||
|
||||
`TrainingLap`:
|
||||
|
||||
```js
|
||||
{
|
||||
id: string,
|
||||
sourceKey: string, // sessionId + passing timestamp + competitor + passing index
|
||||
sessionId: string,
|
||||
sessionName: string,
|
||||
eventId: string,
|
||||
eventName: string,
|
||||
driverId: string,
|
||||
timestamp: number,
|
||||
lapMs: number,
|
||||
recordedAt: string
|
||||
}
|
||||
```
|
||||
|
||||
Normalized by:
|
||||
- `normalizeTrainingState()` wrapper in `src/app.js`
|
||||
- `normalizeTrainingState()` implementation in `src/training_logic.js`
|
||||
- `syncTrainingLedger()` wrapper in `src/app.js`
|
||||
- `syncTrainingLedger()` implementation in `src/training_logic.js`
|
||||
|
||||
Persisted through:
|
||||
- `buildPersistableState()` in `src/app.js`
|
||||
- `applyPersistedStateHelper()` in `src/runtime_services.js`
|
||||
- existing full-state `POST /api/state` backend path
|
||||
|
||||
Derived statistics are intentionally not stored. They are recalculated from `resultsBySession` so corrections and invalidated laps are reflected immediately.
|
||||
Derived statistics are intentionally not stored. They are recalculated from `state.training.ledger`. Before persistence, `saveState()` synchronizes every session currently present in `resultsBySession`: existing rows for those session IDs are replaced from current valid passings, so judging corrections are reflected. Session IDs absent from `resultsBySession` are not removed from the ledger, preserving lifetime totals after archival or deletion.
|
||||
|
||||
Known lifecycle constraint:
|
||||
- deleting historical sessions removes their source passings and therefore lowers calculated lifetime totals
|
||||
- a future immutable training ledger should be introduced before session archival/deletion is used routinely
|
||||
Migration behavior:
|
||||
- older state without `training.ledger` normalizes to an empty ledger
|
||||
- the next `saveState()` imports valid registered-driver laps from all current session results
|
||||
- invalid laps, anonymous transponders, and laps at or below `500 ms` are excluded
|
||||
|
||||
## 15.9 `Settings`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user