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

@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- New `improve` command that generates `improve.csv` — owned cars not yet at a final tune build, sorted by track count
- `normalized_config` field on `BestCarRecord` — maps any tune config to its closest final build (323/233/332)
- `normalize_to_final_build()` function — normalizes tune configs by incrementing the smallest digit until sum reaches 8
- `owned_configs` field on `MyCarsData` — extracts actual player tune config (engineMajor/weightMajor/chassisMajor) from `my_cars.json`
- `owned_configs` field on `CarCounts` — passes player config data through to output functions
- `atomic_write()` helper — writes to a temporary file first, then renames on success (no partial CSV files)
- `empty_my_data()` test helper — creates an empty owned configs map for tests
- Version prefix stripping (`v2c_`/`v1c_`) for config keys at parse time
- `FinalBuild` column in `best.csv`, `very_best.csv`, `wishlist.csv`, `add.csv`, `remove.csv` output files
- Dedup check in `update_best_car` now considers `normalized_config` to prevent same car+config duplicates
### Changed
- `CarCounts.by_rid` key changed from `String` to `(String, String)` for per-config tracking
- `CarCounts.guid_to_rid` changed from `HashMap<String, String>` to `HashMap<String, HashSet<(String, String)>>`
- `compute_car_counts()` now accepts `owned_configs` parameter
- `compare_records()` now sorts by normalized config as secondary key (after RQ, before brand)
- `load_my_cars_data()` now extracts tune config data for locked cards
- CSV output files now include `FinalBuild` column showing the normalized config
- `update_best_car()` tie detection now checks both `car_rid` and `normalized_config`
- Applied `rustfmt` formatting across the entire codebase
### Removed
- `plans/code-review-v2.md` (completed action items)
## [0.3.0] - 2026-05-07
### Added

View file

@ -7,6 +7,7 @@ A comprehensive Rust-based tool for analyzing car performance data in the Top Dr
- **Best Car Analysis**: Find the best performing cars across all tracks and conditions
- **Wishlist Optimization**: Identify cars to add to or remove from your wishlist
- **Collection Cleanup**: Identify cars that can be safely removed from your collection
- **Upgrade Prioritization**: Find owned cars not yet at their final tune build
- **Track-Specific Analysis**: Get detailed performance data for specific tracks and conditions
- **RQ-Based Filtering**: Filter results by car rarity (RQ) levels
- **Multiple Surface Types**: Support for Dry, Wet, Dirt, Snow, and other track conditions
@ -75,6 +76,11 @@ A comprehensive Rust-based tool for analyzing car performance data in the Top Dr
cargo run --bin records -- wishlist
```
6. **Upgrade Prioritization**: Find cars that need upgrading
```bash
cargo run --bin records -- improve
```
## 📖 Usage Guide
### Basic Commands
@ -140,7 +146,7 @@ cargo run --bin records -- wishlist --max-wishlist 500
```bash
cargo run --bin records -- all
```
Generates all 6 CSV files in a single parse pass. Equivalent to running `best`, `trash`, and `wishlist` together, but more efficient.
Generates all 7 CSV files in a single parse pass. Equivalent to running `best`, `trash`, `wishlist`, and `improve` together, but more efficient.
**Output Files:**
```
@ -150,6 +156,7 @@ 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
improve.csv — Owned cars not yet at final build config
```
Supports both `--min-count N` (default 10) and `--max-wishlist M` (default 300):
@ -197,9 +204,10 @@ The analyzer supports multiple track conditions:
| `best` | Generate `best.csv` and `very_best.csv` | `[--min-count N]` |
| `trash` | Generate `trash.csv` (owned cars safe to remove) | None |
| `wishlist` | Generate `wishlist.csv`, `add.csv`, `remove.csv` | `[--min-count N] [--max-wishlist M]` |
| `all` | Generate all 6 CSV files in a single pass | `[--min-count N] [--max-wishlist M]` |
| `all` | Generate all 7 CSV files in a single pass | `[--min-count N] [--max-wishlist M]` |
| `details` | Print detailed timing data for all tracks (stdout) | None |
| `track` | Print best car for specific track (stdout) | `<track_name> <condition> <rq>` |
| `improve` | Generate `improve.csv` (owned cars not at final build) | None |
### Flags
@ -226,12 +234,13 @@ This generates the following output files (all sorted by car RQ):
| File | Format | Description |
|------|--------|-------------|
| `best.csv` | `RQ,Brand,Model,Year,Count` | All cars best on at least one track |
| `very_best.csv` | `RQ,Brand,Model,Year,Count` | Cars best on ≥ min_count tracks |
| `best.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | All cars best on at least one track |
| `very_best.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars best on ≥ min_count tracks |
| `trash.csv` | `RQ,Brand,Model,Year` | Owned cars not best on any track (RQ<80, not prize) |
| `wishlist.csv` | `RQ,Brand,Model,Year,Count` | Ideal wishlist (very_best unowned, capped) |
| `add.csv` | `RQ,Brand,Model,Year,Count` | Cars to add to wishlist |
| `remove.csv` | `RQ,Brand,Model,Year,Count` | Cars to remove from wishlist |
| `wishlist.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Ideal wishlist (very_best unowned, capped) |
| `add.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars to add to wishlist |
| `remove.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars to remove from wishlist |
| `improve.csv` | `RQ,Brand,Model,Year,Target,Count` | Owned cars not yet at final build config |
### Workflow Steps
@ -241,6 +250,7 @@ This generates the following output files (all sorted by car RQ):
4. **Check** `add.csv` for cars worth adding to your wishlist
5. **Clean up** `remove.csv` entries from your wishlist
6. **Sell** cars listed in `trash.csv` that are no longer useful
7. **Upgrade** cars listed in `improve.csv` to their target final build
## 📊 Data Sources
@ -318,16 +328,17 @@ struct Car {
#### Performance Records
```rust
struct BestCarRecord {
car_rid: String, // Car identifier
brand: String, // Manufacturer
only_name: String, // Model name
year: u16, // Year
rq: u8, // Rarity level
config: String, // Tune configuration
time: f64, // Track time
owned: bool, // Whether you own this car
prize: bool, // Whether this is a prize car
guid: String, // Game identifier
car_rid: String, // Car identifier
brand: String, // Manufacturer
only_name: String, // Model name
year: u16, // Year
rq: u8, // Rarity level
config: String, // Original tune config from JSON
normalized_config: String, // Normalized final build (323, 233, or 332)
time: f64, // Track time
owned: bool, // Whether you own this car
prize: bool, // Whether this is a prize car
guid: String, // Game identifier
}
```

View file

@ -25,6 +25,7 @@ src/
│ ├── wishlist.rs # Wishlist command: wishlist.csv, add.csv, remove.csv
│ ├── details.rs # Details command: details.csv
│ ├── track.rs # Track command: stdout query
│ ├── improve.rs # Improve command: improve.csv (owned cars not at final build)
│ └── all.rs # All command: generates all output files
├── parsing/
│ ├── mod.rs # Core parsing: parse_car_times, update_best_car, parse_all_times
@ -69,16 +70,17 @@ pub struct Car {
```rust
#[derive(Debug, Clone)]
pub struct BestCarRecord {
pub car_rid: String, // Car identifier
pub brand: String, // Manufacturer
pub only_name: String, // Model name
pub year: u16, // Year
pub rq: u8, // RQ level
pub config: String, // Tune config (111, 233, etc.)
pub time: f64, // Track time in seconds
pub owned: bool, // User ownership status
pub prize: bool, // Prize car status
pub guid: String, // Game identifier
pub car_rid: String, // Car identifier
pub brand: String, // Manufacturer
pub only_name: String, // Model name
pub year: u16, // Year
pub rq: u8, // RQ level
pub config: String, // Original tune config from JSON (111, 221, 233, etc.)
pub normalized_config: String, // Normalized final build (323, 233, or 332)
pub time: f64, // Track time in seconds
pub owned: bool, // User ownership status
pub prize: bool, // Prize car status
pub guid: String, // Game identifier
}
```
@ -109,21 +111,25 @@ pub struct AnalysisContext {
```rust
pub struct CarCounts {
pub by_rid: HashMap<String, (BestCarRecord, usize)>,
pub guid_to_rid: HashMap<String, String>,
pub by_rid: HashMap<(String, String), (BestCarRecord, usize)>,
pub guid_to_rid: HashMap<String, HashSet<(String, String)>>,
pub car_map: HashMap<String, Car>,
pub car_list: Vec<Car>,
pub owned_configs: HashMap<String, String>,
}
```
**Key grouping**: `by_rid` is keyed by `(car_rid, normalized_config)` so different tune configs of the same car are tracked separately. `guid_to_rid` maps each GUID to all `(rid, config)` pairs it appears under.
#### `MyCarsData`
**Parsed user data from `my_cars.json`**
```rust
#[derive(Debug, Default)]
pub struct MyCarsData {
pub owned: HashSet<String>, // Owned car GUIDs
pub wishlist: HashSet<String>, // Wishlist car GUIDs
pub owned: HashSet<String>, // Owned car GUIDs
pub wishlist: HashSet<String>, // Wishlist car GUIDs
pub owned_configs: HashMap<String, String>, // GUID → actual tune config (e.g., "233")
}
```
@ -183,11 +189,12 @@ pub enum AppError {
- Sorts by: RQ → Brand → Model name
#### `compute_car_counts(ctx: &AnalysisContext, car_list: Vec<Car>) -> CarCounts`
#### `compute_car_counts(ctx: &AnalysisContext, car_list: Vec<Car>, owned_configs: HashMap<String, String>) -> CarCounts`
**Aggregates per-car win counts from analysis context**
- Iterates all entries in the `DashMap`
- Returns `CarCounts` with by_rid, guid_to_rid, car_map, and car_list
- Groups by `(car_rid, normalized_config)` for per-config tracking
- Returns `CarCounts` with by_rid, guid_to_rid, car_map, car_list, and owned_configs
#### `escape_csv_field(field: &str) -> String`
**Escapes a field for safe CSV inclusion**
@ -195,6 +202,14 @@ pub enum AppError {
- Wraps in quotes if field contains comma, quote, newline, or carriage return
- Doubles internal quotes per CSV spec
#### `normalize_to_final_build(config: &str) -> String`
**Normalizes a tune configuration to the closest "final build"**
- The three final builds are `"323"`, `"233"`, and `"332"` (permutations of digits summing to 8)
- For non-standard configs, repeatedly increments the smallest digit until sum reaches 8
- Returns the original string unchanged if config cannot be parsed or sum already ≥ 8
- Version prefixes (`v2c_`, `v1c_`) are stripped at parse time before reaching this function
---
## Records Binary (`src/records.rs`)
@ -221,6 +236,7 @@ CLI entry point. Defines command-line arguments and dispatches to command handle
| `all` | Generate all output files in a single pass | `--min-count N`, `--max-wishlist M` |
| `details` | Generate `details.csv` with all timing data | None |
| `track` | Show best car for specific track/condition/RQ | `<track> <condition> <rq>` |
| `improve` | Generate `improve.csv` (owned cars not at final build) | None |
---
@ -309,7 +325,7 @@ Loads car database, parses all timing files concurrently, and computes car count
#### `write_best_csv(counts)`, `write_very_best_csv(counts, min_count)`
**Generate best car CSV files**
- Format: `RQ,Brand,Model,Year,Count`
- Format: `RQ,Brand,Model,Year,FinalBuild,Count`
- Fields are CSV-escaped
#### `write_trash_csv(counts, owned)`
@ -323,7 +339,16 @@ Loads car database, parses all timing files concurrently, and computes car count
- Computes ideal wishlist once
- Derives all three files from it
- Format: `RQ,Brand,Model,Year,Count`
- Format: `RQ,Brand,Model,Year,FinalBuild,Count`
#### `write_improve_csv(counts) -> Result<usize, AppError>`
**Generate improve CSV file**
- Lists owned cars whose actual player config is not yet a final build (323/233/332)
- Uses actual player config from `my_cars.json`, not timing data configs
- Format: `RQ,Brand,Model,Year,Target,Count`
- Sorted by track count descending (most impactful upgrades first)
- Returns the number of cars written
#### `write_details_csv(ctx)`
**Generate comprehensive timing data CSV**
@ -347,4 +372,4 @@ Loads car database, parses all timing files concurrently, and computes car count
#### `compare_records(a: &BestCarRecord, b: &BestCarRecord) -> std::cmp::Ordering`
**Comparison for BestCarRecord sorting**
- Sorts by: RQ → Brand → Model name
- Sorts by: RQ → Normalized Config → Brand → Model name

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

View file

@ -56,11 +56,17 @@ This document describes the JSON data structures used by the Top Drives Records
"playerDeck": [
{
"cardId": "card_ferrari_f40_1987",
"locked": true
"locked": true,
"engineMajor": 3,
"weightMajor": 2,
"chassisMajor": 3
},
{
"cardId": "card_mclaren_f1_1993",
"locked": false
"locked": false,
"engineMajor": 2,
"weightMajor": 3,
"chassisMajor": 3
}
]
}
@ -73,11 +79,16 @@ This document describes the JSON data structures used by the Top Drives Records
| `playerDeck` | Array | List of user's cards |
| `cardId` | String | Unique card identifier |
| `locked` | Boolean | Whether card is owned (true = owned) |
| `engineMajor` | Number | Engine tune level (optional) |
| `weightMajor` | Number | Weight tune level (optional) |
| `chassisMajor` | Number | Chassis tune level (optional) |
**Processing Logic**:
- Only `locked: true` cards are considered owned
- `cardId` values are matched against car database GUIDs
- Used to mark cars as "owned" in analysis results
- Tune config extracted as `"{engineMajor}{weightMajor}{chassisMajor}"` (e.g., `"323"`)
- Cards with incomplete tune data are skipped for the improve command with a warning
### 3. Individual Car Timing Files (`times/{rid}.json`)
@ -90,7 +101,7 @@ This document describes the JSON data structures used by the Top Drives Records
{
"users": ["Player1", "Player2"],
"data": {
"111": {
"v2c_111": {
"times": {
"laguna_a00": {
"t": 112.45,
@ -246,7 +257,12 @@ let cars: Vec<Car> = serde_json::from_str(&content)?;
// Parse individual car timing file
let json_data: Value = serde_json::from_str(&file_content)?;
if let Some(configurations) = json_data["data"].as_object() {
for (config, entry) in configurations {
for (raw_config, entry) in configurations {
// Strip version prefix (e.g., "v2c_" from "v2c_233")
let config = raw_config
.strip_prefix("v2c_")
.or_else(|| raw_config.strip_prefix("v1c_"))
.unwrap_or(raw_config);
if let Some(times) = entry["times"].as_object() {
for (track_id, details) in times {
// Process each track time
@ -290,8 +306,10 @@ BestCarRecord {
year: car.year,
rq: car.rq,
config: config.clone(),
normalized_config: normalize_to_final_build(&config),
time,
owned: my_cars.contains(&car.guid),
prize: car.prize,
guid: car.guid.clone(),
}
```

View file

@ -86,18 +86,18 @@ cargo run --bin records -- best --min-count 5
`best.csv`:
```csv
RQ,Brand,Model,Year,Count
85,McLaren,F1,1993,15
82,Ferrari,250 GTO,1962,12
80,Lamborghini,Countach,1974,8
75,Porsche,911 Turbo,1975,6
RQ,Brand,Model,Year,FinalBuild,Count
85,McLaren,F1,1993,323,15
82,Ferrari,250 GTO,1962,332,12
80,Lamborghini,Countach,1974,233,8
75,Porsche,911 Turbo,1975,332,6
```
`very_best.csv`:
```csv
RQ,Brand,Model,Year,Count
85,McLaren,F1,1993,15
82,Ferrari,250 GTO,1962,12
RQ,Brand,Model,Year,FinalBuild,Count
85,McLaren,F1,1993,323,15
82,Ferrari,250 GTO,1962,332,12
```
**Understanding the output:**
@ -105,6 +105,7 @@ RQ,Brand,Model,Year,Count
- **Brand**: Car manufacturer
- **Model**: Car model name
- **Year**: Model year
- **FinalBuild**: Normalized tune configuration (323, 233, or 332)
- **Count**: How many times this car was the fastest across different tracks
**Interpretation:**
@ -164,24 +165,24 @@ cargo run --bin records -- wishlist --min-count 5 --max-wishlist 500
`wishlist.csv`:
```csv
RQ,Brand,Model,Year,Count
90,Pagani,Zonda R,2010,18
88,Ferrari,F40,1987,15
87,McLaren,Senna,2018,12
RQ,Brand,Model,Year,FinalBuild,Count
90,Pagani,Zonda R,2010,323,18
88,Ferrari,F40,1987,332,15
87,McLaren,Senna,2018,233,12
```
`add.csv`:
```csv
RQ,Brand,Model,Year,Count
90,Pagani,Zonda R,2010,18
88,Ferrari,F40,1987,15
RQ,Brand,Model,Year,FinalBuild,Count
90,Pagani,Zonda R,2010,323,18
88,Ferrari,F40,1987,332,15
```
`remove.csv`:
```csv
RQ,Brand,Model,Year,Count
75,BMW,M3,2003,3
72,Audi,RS6,2002,2
RQ,Brand,Model,Year,FinalBuild,Count
75,BMW,M3,2003,332,3
72,Audi,RS6,2002,233,2
```
**Action items:**
@ -196,7 +197,7 @@ RQ,Brand,Model,Year,Count
cargo run --bin records -- all
```
**Purpose:** Generates all 6 CSV files in a single parse pass. Equivalent to running `best`, `trash`, and `wishlist` together, but more efficient since data is only parsed once.
**Purpose:** Generates all 7 CSV files in a single parse pass. Equivalent to running `best`, `trash`, `wishlist`, and `improve` together, but more efficient since data is only parsed once.
**Flags:**
- `--min-count N` — Minimum number of tracks for "very best" qualification (default: 10)
@ -214,6 +215,38 @@ cargo run --bin records -- all --min-count 5 --max-wishlist 500
- `wishlist.csv` — Ideal wishlist (very_best unowned, capped)
- `add.csv` — Cars to add to wishlist
- `remove.csv` — Cars to remove from wishlist
- `improve.csv` — Owned cars not yet at final build config
#### Improve Analysis
**Command:**
```bash
cargo run --bin records -- improve
```
**Purpose:** Generates `improve.csv` — owned cars whose actual tune configuration is not yet a final build (323, 233, or 332). Sorted by number of best tracks descending, so the most impactful upgrades appear first.
**Output File:**
`improve.csv`:
```csv
RQ,Brand,Model,Year,Target,Count
90,Pagani,Zonda R,2010,323,18
85,McLaren,F1,1993,332,15
```
**Understanding the output:**
- **RQ**: Car's rarity level
- **Brand**: Car manufacturer
- **Model**: Car model name
- **Year**: Model year
- **Target**: The final build config the player should upgrade to
- **Count**: How many tracks this car is best on (across all its configs)
**Interpretation:**
- Focus on cars with the highest Count first — upgrading them benefits the most tracks
- The Target column shows which of the three final builds (323, 233, 332) to aim for
- Cars already at a final build or maxed config are automatically excluded
#### Detailed Performance Data
@ -285,19 +318,20 @@ cargo run --bin records -- fetch && cargo run --bin records -- all
### What `all` Does
1. **Parses** all timing data in a single pass
2. **Generates** all 6 output CSV files
3. **Sorts** all files by car RQ
2. **Generates** all 7 output CSV files
3. **Sorts** all files by car RQ (and FinalBuild where applicable)
### Output Files
| File | Format | Description |
|------|--------|-------------|
| `best.csv` | `RQ,Brand,Model,Year,Count` | All cars best on at least one track |
| `very_best.csv` | `RQ,Brand,Model,Year,Count` | Cars best on ≥ min_count tracks |
| `best.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | All cars best on at least one track |
| `very_best.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars best on ≥ min_count tracks |
| `trash.csv` | `RQ,Brand,Model,Year` | Owned cars not best on any track (RQ<80, not prize) |
| `wishlist.csv` | `RQ,Brand,Model,Year,Count` | Ideal wishlist (very_best unowned, capped) |
| `add.csv` | `RQ,Brand,Model,Year,Count` | Cars to add to wishlist |
| `remove.csv` | `RQ,Brand,Model,Year,Count` | Cars to remove from wishlist |
| `wishlist.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Ideal wishlist (very_best unowned, capped) |
| `add.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars to add to wishlist |
| `remove.csv` | `RQ,Brand,Model,Year,FinalBuild,Count` | Cars to remove from wishlist |
| `improve.csv` | `RQ,Brand,Model,Year,Target,Count` | Owned cars not yet at final build config |
### Typical Daily Routine
@ -421,7 +455,7 @@ The tool generates CSV files for external analysis. All files are sorted by car
#### "Please provide a command"
**Problem:** No arguments provided
**Solution:** Use `best`, `trash`, `wishlist`, `all`, `details`, `track`, or `fetch`
**Solution:** Use `best`, `trash`, `wishlist`, `all`, `details`, `track`, `improve`, or `fetch`
#### "Could not read my cars file" / "Missing data file"
**Problem:** `my_cars.json` (or another data file) not found or not readable