Single .tsa analysis file: container in the lib, peaks moved from desktop, legacy sidecars migrated - #35
Merged
Merged
Conversation
Phase 1-2 of the single-analysis-file consolidation: - analysis::waveform — the 3-band peaks pyramid moves from the desktop crate into the library (BandPeaks/PeakLevel/NUM_BANDS, now Clone), so downstream apps get waveform peaks without reimplementing the analyzer. - io::tsa — the .tsa container: 28-byte identity header (sample rate, mono length, FNV content hash) + sequential versioned chunks (ARTF = artifact JSON, PEAK = u8-quantized base pyramid level). Unknown tags and unknown chunk versions skip forward-compatibly; duplicates, truncation, and trailing bytes are structural errors; readers never panic on hostile input. Two API layers: bytes (to_bytes/from_bytes/ from_bytes_validated — for blob stores like a library database) and file wrappers with an atomic temp+rename writer. - PreAnalysisArtifact::matches_identity — matches_source semantics for callers that already hold the (rate, length, hash) identity; matches_source now delegates to it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
read/write_preanalysis_json carry #[deprecated] pointing at the io::tsa container (kept working for downstream consumers). The CLI analyze subcommand now writes the full .tsa container — artifact plus waveform peaks — next to the input by default; an explicit -o *.json keeps the legacy format with a deprecation note. --pre-analysis accepts either format, sniffed by magic bytes, with the same warn-and-fall-back contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The load worker now maintains one .tsa container per track instead of .tspeaks + .tsanalysis.json: validated container read up front, legacy JSON artifacts absorbed (skipping re-analysis), peaks recomputed when absent (milliseconds — the .tspeaks parser is not worth keeping), one write before the Track send for crash resilience and one after analysis. Legacy sidecars are deleted only once the on-disk container holds valid artifact + peaks chunks for exactly this audio; Halo's .halo.* variants are never touched. The desktop peaks module and cache are deleted in favor of the library's analysis::waveform and io::tsa. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README's offline pre-analysis example now builds an AnalysisFile (with the bytes-layer note for database-backed apps), the changelog records the breaking CLI default, deprecations, and additions, and ROADMAP Stage 12's hardening surface points at the .tsa loader plus the deprecated JSON path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Consolidates the two per-track sidecars (
.tsanalysis.json+.tspeaks) into a single.tsaanalysis container, owned by the library so downstream apps (Halo) get the same format.io::tsa— chunked binary container: 28-byte identity header (sample rate, mono length, FNV content hash — one identity validated once for every chunk) + versionedARTF(artifact JSON) andPEAK(u8-quantized base pyramid level) chunks. Unknown tags/versions skip forward-compatibly; duplicates, truncation, and trailing bytes are structural errors; readers never panic on hostile input. Two API layers: bytes (AnalysisFile::to_bytes/from_bytes/from_bytes_validated) for apps that store analysis blobs in their own database keyed bycontent_hash, and sidecar file wrappers (read/write_analysis_file,read_analysis_file_validated,analysis_file_path) with atomic temp+rename writes.analysis::waveform— the 3-band waveform peaks pyramid moves from the desktop crate into the library (BandPeaks,PeakLevel,NUM_BANDS, nowClone).read_preanalysis_json/write_preanalysis_jsonare#[deprecated](still working) pointing at the container API.PreAnalysisArtifact::matches_identityadded;matches_sourcedelegates to it.analyzewrites<input>.tsaby default with both chunks (a complete offline pre-analysis tool);-o out.jsonkeeps legacy JSON with a deprecation note;--pre-analysissniffs magic bytes and accepts either format with the existing warn-and-fall-back contract..tsaper track: valid legacy JSON artifacts are absorbed on load (no re-analysis), peaks recompute instead of parsing old.tspeaks(milliseconds), one container write before the Track send (crash resilience) and one after analysis. Legacy sidecars are deleted only once the on-disk container holds valid artifact + peaks chunks for exactly this audio; Halo's.halo.*variants are never touched.Zero new dependencies. Breaking (0.x → minor bump): the CLI default output format changed; changelog records it.
Testing
matches_identityparity,.tsapipeline roundtrip..tsalayout, legacy-JSON migration proven via a marker value (exact float equality is off the table — serde_json's default f64 parse is ±1 ulp), partial-legacy deletion, stale-legacy-not-absorbed, stale-generation persistence.clifeature)/tests/RUSTDOCFLAGS="-D warnings"docs; desktop fmt/clippy/48 tests..tsa(logs:migrating legacy JSON sidecar,Removed superseded legacy sidecar×2,.halo.tsanalysis.jsonuntouched); relaunch = pure container hit; truncated.tsasilently rebuilt. CLI smoke:analyze→ 13.9 KB.tsa,--pre-analysis in.wav.tsavalidates and applies it.🤖 Generated with Claude Code