Commit graph

9 commits

Author SHA1 Message Date
293a8d7707 Add protect/storage lists, dynamic trash thresholds, tie resolution
Protect & storage lists:
- protect.csv: unlocked garage cars (state != 0, locked == false) worth
  locking more copies of. Needed copies = best configs surviving the
  RQ-band thresholds (prize cars and RQ >= 80 always count); already
  locked copies (copy_count) are subtracted, surplus drops off the list.
- storage.csv: Keep/Trash recommendation for storage cars (state == 0)
  using the same copy-count logic; surplus unlocked copies are fusion
  material.
- user_data.rs now parses card state (garage vs storage), garage slots
  (user.garageSlots/garageSlotsUsed), and unlocked card maps.

Dynamic trash thresholds:
- TrashThresholds derive RQ 20-29/30-39 as half/a quarter of a base
  value (--trash-base-count, default 4); RQ 40+ never covered.
- plan_trash_rules escalates the base automatically while projected free
  garage slots (capacity - used + unlocked non-best copies + new trash
  candidates, copies counted per card) stay below --garage-min-free
  (default 20), stopping when no further cars qualify. Effective
  thresholds and projection are printed.
- Improve-based low-value cars (best target count at or below the band
  threshold) land in trash.csv; collect_improve_entries is shared with
  improve.csv and computed once per run.

Same-car tie resolution:
- resolve_tied_configs collapses tie-equivalent configs of the same car
  per track (compute_car_counts, write_details_csv), preferring the
  player's owned final-build config. Fixes phantom rows like the
  Mercedes 280 SL 332 entry tied at 61.31 by its owned 323, inflated
  per-config track counts, and pointless second-copy recommendations.

Wishlist:
- Prize cars are excluded from the ideal wishlist and surface in
  remove.csv via the ideal-set difference.

CLI: new protect command; --trash-base-count/--garage-min-free on
trash/protect/all; details command reuses counts for tie resolution.
README updated for all new files, flags, and criteria.
2026-08-21 18:45:37 +02:00
1a844e7aa8 Address fourth review round: observability, docs accuracy, dep hygiene, tests
- Warn when no timing data was found at all (empty --times-dir previously
  produced empty CSVs without any hint) — best_cars empty + non-empty car
  list now logs a warning in parse_all_times
- Remove the inaccurate "known gap" doc from write_trash_csv: category 1
  (not best on any track) already covers non-final cars, so the
  documented gap never existed
- Gate env_logger behind the bin-logging feature (default-on) and mark
  the records binary as requiring it, so downstream lib consumers do not
  pull env_logger transitively; lib builds clean with --no-default-features
- Switch fetch_car progress output from println! to log::info! so
  RUST_LOG controls it
- atomic_write takes &Path instead of &PathBuf
- Add direct unit tests for is_final_build (sum-8 finals, maxed builds,
  sub-8 non-finals, malformed inputs) and a parsing test covering
  missing/null/non-numeric "t" fields (warn + skip, valid entries still
  parsed)
2026-08-15 20:14:53 +02:00
58b8d23e68 Address full-codebase review: logging boundary, clone elimination, robustness
Library no longer prints to stderr:
- Replace every eprintln! with log::warn! (lib: user_data, http; bin:
  parsing, output, commands); initialize env_logger in main with a
  warn-level default so output is unchanged unless RUST_LOG is set
- Warn on missing/non-numeric "t" time fields instead of silently
  coercing them to 0.0; suppress the per-car NotFound warning (most
  cars legitimately have no timing file), keep warnings for real I/O
  errors

Ownership and clone cleanup:
- CarCounts no longer duplicates the car database: drop the car_list
  field and build car_map by consuming car_list (each Car stored once);
  iterate car_map.values() where the list was previously used
- run_analysis takes MyCarsData by value: owned moves into the parse
  Arc, owned_configs/copy_count move into CarCounts; only the three
  commands that need owned/wishlist afterwards retain their own copy
- is_final_build checks the digits directly (no per-call String
  allocation) and treats malformed configs as non-final so they
  surface in improve.csv; owned_final_configs becomes a borrowed
  rid-to-configs map so the target-exclusion check allocates nothing
- Normalize sum arithmetic to u8 in normalize_to_final_build

Docs and structure:
- Document the first-seen-wins tie-breaking in compute_ideal_wishlist
  and the non-final/non-best coverage gap in write_trash_csv
- Extract compare_by_rq_config_brand_name shared by compare_records
  and the remove.csv sort; drop the unused _output_dir parameter from
  run_track; add a retry_delay helper de-duplicating the three HTTP
  backoff sites; rename the shadowed `entry` binding to config_data
2026-08-15 19:29:51 +02:00
39d1e1d71b Address review findings: const guards, qualifying-count regression test, owned keys
- Add compile-time const assertions (const _: () block, stable on 1.95)
  for MAX_RQ, MIN_VALID_TIME, TIME_TOLERANCE, TEST_BOWL_FACTOR, and
  CONCURRENCY_LIMIT so bad constant edits fail the build; remove the
  stale comment that incorrectly claimed compile-time validation existed
- Add regression test for the qualifying-count fix: car with 3 configs
  where only 2 meet min_count and 2 copies suffice to cover the
  qualifying ones (previously phantom-wishlisted via overcounting)
- Use owned String keys in qualifying_per_guid to decouple the map from
  guid_to_rid's allocations
- Clarify write_improve_csv doc (exactly one row per car), restore the
  remove.csv test section header, add trailing newline to .gitignore
2026-08-15 19:07:03 +02:00
2ab66a249b Fix review findings: wishlist qualifying count, improve docs, and lint cleanup
- 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
2026-08-15 18:58:12 +02:00
fc9f637c60 Generalize config prefix stripping and refactor improve CSV output
- Replace hardcoded v2c_/v1c_ prefix stripping with generic rsplit_once('_')
  approach that handles any prefix (v2b_, v3a_, etc.) while validating
  the suffix is exactly 3 ASCII digits
- Refactor write_improve_csv to emit one row per normalized config per car
  instead of a single aggregated row, giving visibility into all viable
  upgrade paths
- Add 4 new tests covering prefix stripping and improve CSV behavior
2026-05-11 20:16:09 +02:00
bf21d3d1f6 feat: add normalized config tracking and improve command
- 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
2026-05-11 16:23:04 +02:00
67a79f190a Refactor: extract lib.rs into focused sub-modules, add --output-dir CLI option
- Split monolithic src/lib.rs (~640 lines) into 7 sub-modules:
  types.rs, context.rs, user_data.rs, translate.rs, http.rs,
  csv_util.rs, test_utils.rs
- Add configurable --output-dir CLI option for CSV output files
- Implement atomic file writes (write-to-temp + rename) for all CSVs
- Change compute_car_counts() to return CarCounts directly (not Result)
- Add test-utils feature gate for shared test helpers
- Add HTTP mock tests with mockito (6 tests)
- Add proptest tests for compute_car_counts (3 property tests)
- Update integration tests to use shared test utilities
- Update documentation (API.md, ARCHITECTURE.md, DATA_STRUCTURES.md)
2026-05-08 20:21:46 +02:00
a9a46ee551 refactor: modular architecture with unified error handling and DashMap concurrency
- Break monolithic records.rs into commands/, output/, parsing/ modules
- Add lib.rs with shared types (AppError, Car, BestCarRecord, etc.)
- Replace Arc<Mutex<HashMap>> with DashMap for concurrent access
- Add unified AppError enum with thiserror
- Add configurable CLI paths (--my-cars, --cars-db, --times-dir, --tracks-db)
- Add serde deserialization for Car struct
- Add CSV escaping for fields with commas/quotes/newlines
- Fix track name splitting: split_once -> rsplit_once for _a handling
- Add integration tests, proptest property-based tests, and unit tests
- Add rustfmt.toml configuration
- Update documentation (API, ARCHITECTURE, DATA_STRUCTURES, README)
2026-05-08 16:19:01 +02:00