Empty API responses (200 + empty body) mean "known car, no times
submitted yet" on the records site — typically newly released prize
cars. Previously each such car burned 3 retries with backoff and then
aborted the entire fetch; 27 cars in the current DB hit this.
- Add AppError::EmptyResponse { url } as a distinct, deterministic
failure class; get_file fails immediately instead of retrying
- fetch_car downgrades EmptyResponse to a skip with an info log, so
fetch completes; the next fetch picks the cars up automatically
once records exist
- parse_car_times treats empty (or whitespace-only) timing files
like missing files, eliminating "EOF while parsing a value at line
1 column 0" parse errors from stale empty files
trash.csv Config column now lists only the copies to delete: for a
car whose one tune is a final build not best on any track (e.g.
owned 332 next to a best-on-213-tracks 323), only the dead tune is
shown instead of joining all owned configs. Categories 1 and 3 still
list all configs since the whole car goes.
Tests: empty response makes exactly 1 request and yields the
EmptyResponse variant; empty file parses Ok; partial-copy trash
shows only the deletable config.
- Gate env_logger init behind #[cfg(feature = "bin-logging")] in
records.rs main() so the binary respects the feature flag
- Set default-features = false on the dev-dependency self-reference
in Cargo.toml; previously default features were silently re-enabled
during tests, making feature isolation accidental rather than real
- Bind guid.to_string() once per card in user_data.rs deck loop and
reuse it via clone, replacing three allocations per locked card
- Add per-field help text to the Track subcommand args clarifying
human-readable names ("Laguna Seca", "Dry") vs raw codes
- Document write_details_csv DashMap snapshot memory tradeoff
(full clone, roughly doubled peak memory during the write)
- Extend my_cars fixture test: duplicate guids count as 2 copies
with per-copy configs, and incomplete-tune cards still count in
copy_count
- Count only configs meeting min_count as qualifying in the wishlist
copy-coverage check (previously ALL guid_to_rid entries inflated the
denominator, producing phantom wishlist entries), pre-computed once
per guid instead of per record
- Update stale write_improve_csv doc to match single-best-target
behavior including cross-copy exclusion
- Borrow owned configs for the trash CSV join instead of cloning the Vec
- Build owned_final_configs via filter_map + flat_map without the
throwaway intermediate Vec
- Remove runtime assertions on literal constants (clippy
assertions_on_constants) and replace a redundant closure with the
function reference (clippy redundant_closure)
- Apply rustfmt across the crate and drop a duplicated test-section header
- Change owned_configs from HashMap<String, String> to HashMap<String, Vec<String>>
to capture all configs across copies (previously last-write-wins lost data)
- Add copy_count field to MyCarsData and CarCounts for wishlist copy-coverage logic
- Fix improve.csv to exclude already-owned final configs as targets (e.g., Fiat
Campagnola 1974 now targets 332 instead of already-owned 323)
- Fix wishlist to check all owned configs for exact-match and final-build detection
- Fix trash to check all configs for final-build-not-best detection
- Update all tests for new Vec type and add multi-copy improve test
- Add normalize_to_final_build() to map tune configs to final builds (323/233/332)
- Add normalized_config field to BestCarRecord
- Change CarCounts.by_rid key from String to (String, String) for per-config tracking
- Change CarCounts.guid_to_rid to HashMap<String, HashSet<(String, String)>>
- Extract owned tune configs from my_cars.json (engineMajor/weightMajor/chassisMajor)
- Add improve command: owned cars not yet at final build, sorted by track count
- Strip version prefixes (v2c_/v1c_) from config keys at parse time
- Update dedup check in update_best_car to consider normalized_config
- Add atomic_write helper for safe CSV output
- Delete completed plans/code-review-v2.md
- Apply rustfmt formatting across codebase