acorde-analysis 1.2.5

Deterministic, explainable music analysis for acorde scores
Documentation

acorde-analysis

Deterministic, explainable analysis primitives for acorde-core. The crate has no I/O, renderer, or host dependencies.

The capability slice labels chord-shaped pitch collections, records adjacent melodic intervals (including exact signed microtonal cents), does not bridge rests or pitchless events, and estimates major/minor keys from duration-weighted diatonic pitch coverage. It also reports explicit cadence transitions and aligned voice-leading observations, including parallel-perfect flags. Every result contains stable NoteAddr evidence and a rule identifier. Voice-leading observations retain exact signed cents for microtonal motion. SATB diagnostics classify voice crossing, wide spacing, and parallel-perfect motion with typed severity. Key estimation returns all tied best candidates, so relative-major/minor ambiguity is preserved instead of inventing a single key. Repeated three-note interval motifs and explicit rest-terminated phrase boundaries are also reported with source spans.

use acorde_analysis::analyze_score;
use acorde_core::Score;

let result = analyze_score(&Score::default());
assert!(result.chords.is_empty());

analyze_batch preserves input order for finite collections, while analyze_stream returns a lazy iterator for host-side streaming. Both use the same deterministic result contract.

AnalysisCache provides a bounded deterministic in-memory cache keyed by the schema-versioned score fingerprint. Editing any canonical score content produces a cache miss automatically; eviction is insertion-order based and does not depend on hash-map iteration. Its analyze_batch method preserves input order while reusing duplicate or previously cached scores. Editors can call invalidate(score) after dropping an old score snapshot to reclaim that entry without disturbing other cached results. stats() exposes deterministic hit/miss counters, and reset_stats() clears only those counters for host-side measurement windows. For an editor replacement flow, analyze_after_edit(previous, current) reclaims the previous snapshot and returns the analysis for the current score in one operation. When both snapshots have the same canonical fingerprint, the helper keeps and reuses the existing entry instead of forcing an unnecessary recomputation.

diff_analysis(previous, current) reports changed result categories in stable order while keeping score fingerprint changes separate from category changes. This lets hosts update explanations or views selectively without treating metadata-only edits as analysis-content changes. analysis_provenance(result, address) returns the deterministic rule ID, confidence, and source evidence for every finding that contains the selected NoteAddr. explain_analysis_change(previous, current, address) combines before/after provenance with the deterministic category diff for an explainable editor update.

Offline benchmark consumers can use BenchmarkCase and run_benchmark with hand-verified category counts. The report includes predicted counts, precision, recall, explanation completeness, and category-level BenchmarkFailure records with missing or excess predictions. run_benchmark_suite additionally aggregates case status and metrics; an empty suite is reported as zero for each aggregate metric. Latency should be measured by the host benchmark runner and is intentionally not embedded in the deterministic analysis result.

Applications can register deterministic extensions with AnalysisPass and execute them through run_analysis_passes. Pass IDs are validated and sorted before execution, so results do not depend on registration order; empty or duplicate IDs return AnalysisPassError.

Analysis resource-budget ownership is documented in the security contract.