docs: update documentation for normalized config and improve command

- Add improve command to all command tables and usage sections
- Add normalized_config field to BestCarRecord struct documentation
- Update CarCounts.by_rid type from String to (String, String)
- Update CarCounts.guid_to_rid type to HashMap<String, HashSet<(String, String)>>
- Add owned_configs field to MyCarsData and CarCounts docs
- Add normalize_to_final_build() to API docs
- Update CSV format examples to include FinalBuild column
- Update my_cars.json structure with engineMajor/weightMajor/chassisMajor
- Update timing file example with v2c_ version prefix
- Add version prefix stripping to data transformation docs
- Update CHANGELOG.md with Unreleased section
- Fix compare_records description to include normalized config sorting
This commit is contained in:
Jan-Peter von Hunnius 2026-05-11 16:58:01 +02:00
parent bf21d3d1f6
commit 2b0602d564
6 changed files with 204 additions and 84 deletions

View file

@ -14,13 +14,13 @@ The Top Drives Records Analyzer is a Rust CLI tool for analyzing car performance
| Module | File | Key Exports |
|--------|------|-------------|
| `types` | `src/types.rs` | `AppError`, `BestCarRecord`, `Car`, `TripletKey` |
| `types` | `src/types.rs` | `AppError`, `BestCarRecord`, `Car`, `TripletKey`, `normalize_to_final_build` |
| `context` | `src/context.rs` | `AnalysisContext`, `CarCounts`, `compute_car_counts` |
| `user_data` | `src/user_data.rs` | `MyCarsData`, `load_my_cars_data` |
| `translate` | `src/translate.rs` | `translate_track_name`, `translate_track_type` |
| `http` | `src/http.rs` | `get_file` |
| `csv_util` | `src/csv_util.rs` | `compare_cars`, `escape_csv_field` |
| `test_utils` | `src/test_utils.rs` | `make_record`, `make_car` (test helpers) |
| `test_utils` | `src/test_utils.rs` | `make_record`, `make_car`, `empty_my_data` (test helpers) |
#### Error Handling
All public functions return `Result<T, AppError>` where `AppError` is a unified error type:
@ -58,6 +58,7 @@ All public functions return `Result<T, AppError>` where `AppError` is a unified
| `wishlist.rs` | `wishlist` | Generates `wishlist.csv`, `add.csv`, `remove.csv` |
| `details.rs` | `details` | Generates `details.csv` with all timing data |
| `track.rs` | `track` | Prints best car for a specific track/condition/RQ |
| `improve.rs` | `improve` | Generates `improve.csv` (owned cars not yet at final build) |
| `all.rs` | `all` | Generates all output files in a single analysis pass |
#### Shared Helpers (`src/commands/mod.rs`)
@ -86,14 +87,16 @@ All public functions return `Result<T, AppError>` where `AppError` is a unified
**CSV output utilities** and sorting helpers.
- `write_sorted_csv()` — Generic sorted CSV writer (index-based sorting to avoid cloning)
- `atomic_write()` — Writes to a temporary file first, then renames on success (no partial files)
- `write_sorted_csv()` — Generic sorted CSV writer (index-based sorting to avoid cloning, uses `atomic_write`)
- `write_best_csv()`, `write_very_best_csv()` — Best car CSV output
- `write_trash_csv()` — Trash car CSV output
- `write_details_csv()` — Comprehensive timing data CSV output
- `write_wishlist_files()` — Wishlist, add, and remove CSV output
- `write_improve_csv()` — Improve car CSV output (owned cars not yet at final build)
- `print_best_car()` — Stdout output for track-specific query
- `compute_ideal_wishlist()` — Ideal wishlist computation
- `compare_records()` — Sorting comparator for `BestCarRecord`
- `compare_records()` — Sorting comparator for `BestCarRecord` (by RQ, normalized config, brand, model)
#### Data Flow
@ -146,16 +149,17 @@ struct Car {
#### BestCarRecord
```rust
struct BestCarRecord {
car_rid: String, // Car identifier
brand: String, // Manufacturer
only_name: String, // Model name
year: u16, // Year
rq: u8, // RQ level
config: String, // Tune config (111, 233, etc.)
time: f64, // Track time (seconds)
owned: bool, // User ownership status
prize: bool, // Prize car status
guid: String, // Game identifier
car_rid: String, // Car identifier
brand: String, // Manufacturer
only_name: String, // Model name
year: u16, // Year
rq: u8, // RQ level
config: String, // Original tune config from JSON (111, 221, 233, etc.)
normalized_config: String, // Normalized final build (323, 233, or 332)
time: f64, // Track time (seconds)
owned: bool, // User ownership status
prize: bool, // Prize car status
guid: String, // Game identifier
}
```
@ -175,15 +179,17 @@ struct AnalysisContext {
### CarCounts
```rust
struct CarCounts {
by_rid: HashMap<String, (BestCarRecord, usize)>,
guid_to_rid: HashMap<String, String>,
by_rid: HashMap<(String, String), (BestCarRecord, usize)>,
guid_to_rid: HashMap<String, HashSet<(String, String)>>,
car_map: HashMap<String, Car>,
car_list: Vec<Car>,
owned_configs: HashMap<String, String>,
}
```
**Purpose**: Aggregated per-car win counts computed once from `AnalysisContext`
**Usage**: Shared across all output functions to avoid redundant computation
**Key grouping**: `by_rid` is keyed by `(car_rid, normalized_config)` so different tune configs of the same car are tracked separately.
## Algorithm Details
@ -241,7 +247,8 @@ Multiple validation layers ensure data quality:
├── trash.csv # Owned cars safe to remove
├── wishlist.csv # Ideal wishlist (very_best unowned, capped)
├── add.csv # Cars to add to wishlist
└── remove.csv # Cars to remove from wishlist
├── remove.csv # Cars to remove from wishlist
└── improve.csv # Owned cars not yet at final build config
```
## Performance Characteristics