fix(analysis): native library backfill coordinator for advanced strategy (#881)

* feat(analysis): native library backfill coordinator for advanced strategy

Move advanced analytics scheduling from the webview loop into a Rust
background worker (configure + spawn_blocking batch/enqueue), matching
cover backfill. Scan hash+BPM gap tracks instead of the full library;
suppress low-priority analysis UI events; limit loudness refresh IPC to
the playback window.

* fix(analysis): flat backfill configure IPC and restore probe track-perf

Use flattened Tauri args like cover backfill so release/prod invoke works;
keep emitting analysis:track-perf for library low-priority work so Performance
Probe tpm/last-track stats update while waveform/enrichment UI events stay suppressed.

* chore(analysis): fix clippy and drop duplicate TS backfill policy

Allow too_many_arguments on library_analysis_backfill_configure for CI;
remove unused frontend batch API and TS watermark helpers now owned in Rust;
clarify analysis_emits_ui_events comment for low-priority track-perf.

* docs: CHANGELOG and credits for PR #881 native analysis backfill
This commit is contained in:
cucadmuh
2026-05-28 10:49:31 +03:00
committed by GitHub
parent df3533bb5a
commit b24a7fc5cb
21 changed files with 888 additions and 387 deletions
@@ -47,6 +47,7 @@ pub fn seed_from_bytes_execute<R: Runtime>(
server_id: &str,
track_id: &str,
bytes: &[u8],
notify_ui: bool,
) -> Result<(SeedFromBytesOutcome, AnalysisSeedTimings), String> {
let seed_started = Instant::now();
let Some(cache) = app.try_state::<AnalysisCache>() else {
@@ -84,6 +85,7 @@ pub fn seed_from_bytes_execute<R: Runtime>(
server_id,
track_id,
bytes,
notify_ui,
);
if matches!(enrichment_outcome, TrackEnrichmentOutcome::Failed) {
let key = TrackKey {
@@ -1233,7 +1235,7 @@ mod tests {
let app = tauri::test::mock_app();
let wav = build_mono_pcm16_wav(&sine_440_at_minus_6db(44_100, 0.25), 44_100);
let handle = app.handle().clone();
let (outcome, timings) = seed_from_bytes_execute(&handle, "s", "t", &wav)
let (outcome, timings) = seed_from_bytes_execute(&handle, "s", "t", &wav, true)
.expect("seed execute should return a graceful skip");
assert_eq!(outcome, SeedFromBytesOutcome::SkippedNoAnalysisCache);
assert_eq!(timings.seed_ms, 0);
@@ -1248,12 +1250,12 @@ mod tests {
let handle = app.handle().clone();
let (first, timings_first) =
seed_from_bytes_execute(&handle, "server-a", "track-exec", &wav).unwrap();
seed_from_bytes_execute(&handle, "server-a", "track-exec", &wav, true).unwrap();
assert_eq!(first, SeedFromBytesOutcome::Upserted);
assert!(timings_first.seed_ms <= 30_000);
let (second, timings_second) =
seed_from_bytes_execute(&handle, "server-a", "track-exec", &wav).unwrap();
seed_from_bytes_execute(&handle, "server-a", "track-exec", &wav, true).unwrap();
assert_eq!(second, SeedFromBytesOutcome::SkippedWaveformCacheHit);
assert!(timings_second.seed_ms <= 30_000);
}