Skip to content

release: v2.11.0 — deep sweep: crash fixes, data-correctness fixes, perf overhaul, settings persistence#75

Merged
SomethingNew71 merged 18 commits into
mainfrom
release/v2.11.0
Jul 16, 2026
Merged

release: v2.11.0 — deep sweep: crash fixes, data-correctness fixes, perf overhaul, settings persistence#75
SomethingNew71 merged 18 commits into
mainfrom
release/v2.11.0

Conversation

@SomethingNew71

Copy link
Copy Markdown
Collaborator

Summary

Deep sweep of the app ahead of v2.11.0: crash and data-correctness fixes across the parsers and app state, a per-frame performance overhaul, settings persistence, dependency refresh, and a CLAUDE.md rewrite to match the current codebase.

Bug fixes

  • speeduino: truncated MLG v2 headers panicked with index-out-of-bounds; bounds-checked before reads. Parser debug output moved from eprintln! to tracing.
  • app: a parser panic on the loader thread left the UI stuck on the loading spinner forever; disconnected receivers now surface an error toast.
  • haltech: unparseable fields (blank, N/A, text gears) compacted the row left, misaligning every later column — now filled with last-known-value like the ECUMaster parser.
  • haltech: sessions crossing midnight produced non-monotonic times, breaking the binary search behind time-shifted computed channels (RPM@-0.1s).
  • normalize: a channel named Speed normalized to RPM or Vehicle Speed nondeterministically per launch (HashMap iteration-order collision); ambiguous RPM alias removed.
  • app: opening a file while another was loading silently dropped the first result; loads now queue, and multi-file drag-drop loads every file instead of only the first.
  • app: analysis_results were not reindexed on file removal, attaching cached analyses to the wrong file.
  • adapters: API-supplied vendor/id are sanitized to a filename-safe slug before cache writes (path-traversal hardening).

Performance

  • Event-driven IPC: the MCP/IPC server previously forced a 10 Hz repaint forever (idle battery drain); the GUI now wakes via a repaint callback when a command arrives.
  • Chart downsample cache: the O(samples) downsample re-ran for every channel every frame; now cached per channel and recomputed only when the quantized viewport changes.
  • Scatter heatmap cache: two full channel copies + a 512×512 histogram rebuilt per frame; now built once per axis selection.
  • Dark visuals applied once at startup instead of per frame; codegen-units = 1 for release builds.

Features

  • Settings persistence: unit preferences, font scale, colorblind mode, field normalization, cursor tracking, auto-update check, and custom channel mappings now survive restarts (previously all silently reset — the wiki claimed font size was saved when it was not).
  • Documented-but-missing shortcuts added: Esc stops playback, Cmd+E exports the current view as PNG.

Chores

  • Semver-compatible cargo update; stale .bak files removed from src/ui/; version bumped to 2.11.0.
  • CLAUDE.md rewritten to cover the analysis/ipc/mcp modules, all 14 parsers, new UI panels, and the new settings-persistence and cache-invalidation contracts.

Test plan

  • Full suite green: 918 passed, 0 failed (3 new regression tests: haltech column alignment, haltech midnight rollover, speeduino truncated v2 header).
  • cargo fmt --all -- --check and cargo clippy -- -D warnings clean.

Deferred (follow-ups, not in this PR)

  • Major dep bumps: eframe 0.35 / egui_plot 0.36 / egui_extras 0.35, printpdf 0.11, rust-i18n 4.x, rmcp 2.x — each as its own PR.
  • meval replacement (unmaintained; its nom 1.2.4 dep is flagged future-incompatible by rustc).
  • Updater hardening (checksum/signature verification, temp-path TOCTOU).

…; apply dark visuals once at startup; surface loader-thread panics as an error toast instead of hanging in Loading state
…2 files panicked with index out of bounds; also route parser debug output through tracing instead of eprintln
…sults attached to the wrong file after deletion
…ith Vehicle Speed in the reverse map, making normalization nondeterministic across launches
… unparseable values previously compacted the row left, misaligning every later column; now last-known-value is substituted like the ECUMaster parser
…, field normalization, cursor tracking, auto-update check, and custom channel mappings — previously all of these silently reset every launch; synced via eframe's auto-save hook
…quantized viewport — the O(samples) downsample previously re-ran for every channel every frame; now it only recomputes when the anchored bucket grid shifts. Cache is invalidated on file removal and computed-channel deletion (minmax cache too, same index-shift staleness)
…ening a second file while one was loading silently lost the first; multi-file drag-drop now loads every file instead of only the first. Also add documented-but-missing shortcuts: Esc stops playback, Cmd+E exports the current view as PNG
…lug before writing spec cache files — a hostile or corrupt API response could otherwise escape the cache directory via path separators
…sions crossing midnight produced non-monotonic times, breaking the binary search used by time-shifted computed channels
…ously two full channel copies plus a 512x512 histogram rebuild ran every frame; now only on selection change
…/ipc/mcp modules, all 14 parsers, new UI panels, settings-persistence and cache-invalidation contracts, keyboard shortcuts, current dependencies
Copilot AI review requested due to automatic review settings July 16, 2026 15:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Pre-release sweep for v2.11.0 focused on improving robustness (parser crash/correctness fixes), reducing per-frame CPU cost via caching and event-driven IPC, and persisting user-facing preferences across restarts.

Changes:

  • Added regression tests for Speeduino truncated v2 headers and Haltech column-alignment + midnight rollover cases.
  • Implemented settings persistence (new UserSettings fields + eframe::App::save synchronization) and converted several preference types to Serialize/Deserialize.
  • Introduced performance-oriented caches: chart downsample caching keyed by a quantized viewport key, and a cached scatter-heatmap histogram built once per axis selection; replaced IPC polling repaint with a repaint callback.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/parsers/speeduino_tests.rs Adds regression test ensuring truncated v2 headers error instead of panicking.
tests/parsers/haltech_tests.rs Adds regression tests for Haltech unparseable-field alignment and midnight rollover monotonicity.
tests/core/settings_tests.rs Updates settings tests to include new persisted fields via ..UserSettings::default().
src/units.rs Makes unit preference enums/struct serializable for persistence.
src/ui/scatter_plot.rs Caches scatter heatmap histograms per (file, x, y) to avoid rebuilding every frame.
src/ui/histogram.rs.backup Removes stale backup file from the repo.
src/ui/export.rs.bak Removes stale backup file from the repo.
src/ui/chart.rs Adds per-channel downsample caching keyed by a quantized viewport key; reduces per-frame downsample work.
src/state.rs Introduces cache types (DownsampleCache, ScatterHistogramCache) and DownsampleViewKey; makes FontScale serializable.
src/settings.rs Expands UserSettings for persisted preferences (units, font scale, normalization, etc.) and derives PartialEq for change detection.
src/parsers/speeduino.rs Adds explicit v2 header truncation check and migrates debug output to tracing.
src/parsers/haltech.rs Preserves column alignment by using last-known-value substitution; adds midnight rollover handling for monotonic times.
src/normalize.rs Removes ambiguous "Speed" alias from RPM normalization map to avoid nondeterministic collisions.
src/ipc/server.rs Adds repaint callback to wake the GUI on command arrival (event-driven IPC).
src/ipc/handler.rs Clears chart caches when computed channels are removed to avoid index-based cache staleness.
src/app.rs Applies dark theme once at startup, queues file loads, improves loader disconnect handling, persists settings on save, and switches IPC handling to event-driven repaint.
src/adapters/cache.rs Sanitizes API-supplied vendor/id into a filename-safe slug to harden cache writes against path traversal.
CLAUDE.md Updates architecture/developer documentation to match current modules and new persistence + caching contracts.
Cargo.toml Bumps version to 2.11.0 and sets codegen-units = 1 for release builds.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ui/chart.rs
Comment on lines +888 to +916
// Derive the cache key for this viewport. The bucketed downsampler
// below is anchored to a fixed grid, so its output only changes when
// the first bucket index or the bucket width changes — steady frames
// (idle, cursor moves within a bucket) reuse the cached points.
let n_buckets = (MAX_CHART_POINTS / 2).max(1);
let view_key = match viewport {
Some((vmin, vmax)) if vmax > vmin => {
let pad = (vmax - vmin) * 0.1;
let padded_span = (vmax - vmin) + 2.0 * pad;
let bucket_size = padded_span / n_buckets as f64;
if bucket_size <= 0.0 {
DownsampleViewKey::Full
} else {
let raw_lo = vmin - pad;
DownsampleViewKey::Bucketed {
k_lo: (raw_lo / bucket_size).floor() as i64,
bucket_bits: bucket_size.to_bits(),
}
}
}
_ => DownsampleViewKey::Full,
};

if let Some((cached_key, points)) = self.downsample_cache.get(&(file_index, channel_index))
{
if *cached_key == view_key {
return Some(points.clone());
}
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 05e0c99 — the cache key now includes plot_area_id, so a channel shown in two stacked plots with different viewports keeps separate entries instead of evicting itself each frame.

@SomethingNew71
SomethingNew71 merged commit 68e46ef into main Jul 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants