Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,20 +183,20 @@ TEST_FLAC_PATH=/path/to/track.flac GEMINI_API_KEY=… VITE_ENABLE_PHASE2_GEMINI=
Operational and one-shot scripts live in two places. They are not on the request-path; reach for them when the situation calls for it.

`scripts/` (repo root):
1. `dev.sh` — full-stack dev launcher (covered above).
2. `test-e2e.sh` / `test-e2e-integration.sh` — e2e harnesses (covered above).
1. `dev.sh` — full-stack dev launcher (covered above). Covered by `apps/backend/tests/test_root_dev_script.py`.
2. `test-e2e.sh` / `test-e2e-integration.sh` — e2e harnesses (covered above). Covered by `apps/backend/tests/test_root_e2e_script.py`.
3. `calibrate_confidence.py` — threshold-sweep harness for the pitch / chord / sidechain detectors. Research-only. Its unit test lives in `scripts/tests/test_calibrate_confidence.py`.
4. `build_live12_catalogue.py` — regenerates `data/live12_catalogue.json` (the source-extracted Live 12 device/parameter catalogue) from the upstream `gluon/AbletonLive12_MIDIRemoteScripts` checkout. Static AST extraction; carries no proprietary code. Re-run when the upstream commit shifts or the schema bumps; the published `data/live12_catalogue.schema.json` validates the output.

`apps/backend/scripts/`:
1. `bootstrap.sh` — recreate the Python 3.11 venv (covered above). `dev.sh` here is a thin shim that `exec`s the repo-root `scripts/dev.sh` full-stack launcher.
1. `bootstrap.sh` — recreate the Python 3.11 venv (covered above). `dev.sh` here is a thin shim that `exec`s the repo-root `scripts/dev.sh` full-stack launcher. `bin/asa` script contracts (install, bootstrap, cleanup) are covered by `apps/backend/tests/test_bootstrap_scripts.py`.
2. `render_upload_limit_contract.py` — regenerate the operator-facing upload-limit contract text from `upload_limits.py`. Run after changing the canonical limits.
3. `evaluate_phase1.py`, `evaluate_polyphonic.py`, `evaluate_structure_sweep.py`, `evaluate_beats.py`, `evaluate_loudness_recs.py`, `evaluate_recommendations.py`, `evaluate_phase2_providers.py` — offline evaluation harnesses for the Phase 1 detector battery, the research polyphonic transcriber, structure-segmentation parameter sweeps, the beat/downbeat measurement gate, loudness-recommendation reachability, the recommendation-quality scorer (`GOAL.md`'s recommendation-proof campaign — scores Phase 2 recs against the `tests/fixtures/recommendation_tracks/` answer-key corpus), and the Phase 2 provider comparison harness (benchmarks Gemini vs MOSS output quality and latency). Wired to `phase1_evaluation.py` / `polyphonic_evaluation.py` / `beat_evaluation.py` / `loudness_rec_evaluation.py` / `recommendation_evaluation.py` / `phase2_provider_evaluation.py`. `build_beat_manifest.py` assembles the beat-eval corpus manifest. `emit_deterministic_recs.ts` is the recommendation harness's deterministic-source bridge (Node 23+ native TS; wraps `apps/ui/src/data/abletonDevices.ts` to score the free path). All research-only. The beat gate's optional neural deps (`beat_this`, `mir_eval`) live in `apps/backend/requirements-eval.txt` — install into a separate venv, never the product venv. The optional MSST separation backend follows the same isolation rule but more strictly: `apps/backend/requirements-msst.txt` is a setup-pointer (not a pinned list) because MSST brings its own conflicting torch/numpy/librosa — it lives in its own venv built from MSST-WebUI's own `requirements.txt`, reached only via the `scripts/msst_separate_runner.py` subprocess (see `separation_backend.py`), never imported into the product venv.
4. `audit_pass1.py`, `genre_check.py`, `replay_catalog_validation.py` — corpus auditing and Live 12 device-catalog validation. `genre_corpus.md` is the corpus manifest.
4. `audit_pass1.py`, `genre_check.py`, `replay_catalog_validation.py` — corpus auditing and Live 12 device-catalog validation. `genre_corpus.md` is the corpus manifest. `genre_check.py` is covered by `apps/backend/tests/test_genre_check.py`.
5. `import_midi_to_ground_truth.py`, `score_polyphonic_clip.py` — corpus-building helpers for the transcription/polyphonic ground-truth fixtures (`tests/fixtures/transcription_tracks/`, `tests/fixtures/polyphonic_tracks/`). Research-only; see those fixtures' READMEs and `docs/LAYER2_EVALUATION.md` / `docs/POLYPHONIC_TRANSCRIPTION_SPIKE.md`.
6. `parity_probe_synth_backends.py` — maintainer probe that renders the same `ClipPlan` through FluidSynth and `symusic.Synthesizer` and reports RMS/peak/spectral-centroid deltas before flipping the `ASA_SAMPLE_SYNTH_BACKEND` auto default. Research/operator-only; not invoked by the runtime.
7. `msst_separate_runner.py` — the MSST separation runner invoked by `separation_backend.py` as a subprocess under `ASA_MSST_PYTHON`. **Runs in the MSST venv, not the product venv** — it imports `MSSeparator` from a `SUC-DriverOld/MSST-WebUI` checkout, writes canonical `vocals/bass/drums/other` 44.1 kHz WAVs, and prints a single-line JSON manifest to stdout. Operator tooling; not a product-venv module.
8. `ab_separation_backends.py` — A/B harness CLI (wraps `separation_ab.py`) comparing the Demucs vs MSST separation backends on quality and runtime: an always-available synthetic SI-SDR smoke-test plus optional real-track reference-free proxies. Writes `.runtime/separation_ab/report.json`. Research-only; deleting `separation_ab.py` restores the product exactly.
8. `ab_separation_backends.py` — A/B harness CLI (wraps `separation_ab.py`) comparing the Demucs vs MSST separation backends on quality and runtime: an always-available synthetic SI-SDR smoke-test plus optional real-track reference-free proxies. Writes `.runtime/separation_ab/report.json`. Research-only; deleting `separation_ab.py` restores the product exactly. `separation_ab.py` logic is covered by `apps/backend/tests/test_separation_ab.py`.

## Architecture

Expand Down Expand Up @@ -283,8 +283,8 @@ Artifact access goes through `artifact_storage.py` rather than direct disk paths
13. **`stage_status.py`**: Collapses the eight internal stage statuses into the additive client-facing `publicStatus` field on every stage snapshot.
14. **`server_samples.py` + `sample_generation.py`, `sample_theory.py`, `sample_synthesis.py`, `sample_drums.py`**: Phase 3 audition-sample generation. `sample_theory.py` builds the PyTheory musical plan, `sample_synthesis.py` renders audio (FluidSynth with sine-additive fallback), `sample_drums.py` synthesizes drum one-shots, `sample_generation.py` orchestrates and emits the citation manifest. On-demand only.
15. **`dsp_bandbank.py` + `dsp_utils.py`**: Shared DSP primitives — `BatchedBandpass` (4th-order Butterworth bandpass bank) and cross-module utility functions.
16. **`phase1_evaluation.py` + `phase1_report_html.py`, `polyphonic_evaluation.py`, `beat_evaluation.py` + `beat_report_html.py`, `loudness_rec_evaluation.py`, `recommendation_evaluation.py`, `phase2_provider_evaluation.py`**: Offline evaluation harnesses (deterministic-metric / detector-stability reporting, research-only polyphonic transcription, the beat/downbeat measurement gate that benchmarks CPJKU/beat_this against the shipping kick-accent heuristic, loudness-recommendation reachability, the recommendation-quality scorer that grades Phase 2 recommendations against known-settings fixtures, and the Phase 2 provider comparison harness that benchmarks Gemini vs MOSS output quality — see [`apps/backend/NEEDS.md`](apps/backend/NEEDS.md)). Not on the product path; driven by `scripts/evaluate_*.py`. Deleting them restores the product exactly.
17. **`utils/cleanup.py`**: Periodic artifact-cleanup helpers used by the server background-task loop.
16. **`phase1_evaluation.py` + `phase1_report_html.py`, `polyphonic_evaluation.py`, `beat_evaluation.py` + `beat_report_html.py`, `loudness_rec_evaluation.py`, `recommendation_evaluation.py`, `phase2_provider_evaluation.py`**: Offline evaluation harnesses (deterministic-metric / detector-stability reporting, research-only polyphonic transcription, the beat/downbeat measurement gate that benchmarks CPJKU/beat_this against the shipping kick-accent heuristic, loudness-recommendation reachability, the recommendation-quality scorer that grades Phase 2 recommendations against known-settings fixtures, and the Phase 2 provider comparison harness that benchmarks Gemini vs MOSS output quality — see [`apps/backend/NEEDS.md`](apps/backend/NEEDS.md)). Not on the product path; driven by `scripts/evaluate_*.py`. Deleting them restores the product exactly. The Layer 2 transcription path of `phase1_evaluation.py` has dedicated pure-function coverage in `tests/test_phase1_evaluation_transcription.py`.
17. **`utils/cleanup.py`**: Periodic artifact-cleanup helpers used by the server background-task loop. Covered by `tests/test_cleanup.py`.
18. **`transcription_pianoroll.py`**: Renders the pitch-note translation stage's `transcriptionDetail` as a velocity-encoded `(pitch, time)` uint8 matrix via [`symusic`](https://github.com/Yikai-Liao/symusic). Backs `GET /api/analysis-runs/{run_id}/transcription/pianoroll`. Derived view, never overrides Phase 1; the response cites Phase 1's `bpm` + `timeSignature` so chain of custody is preserved. Note: `transcriptionDetail` is *stripped* from `measurement.result` (see `analysis_runtime.py` ~L800) and lives in the `pitchNoteTranslation` stage instead — the route reads from there.
19. **`mt3_transcription.py`**: Optional polyphonic transcription via Google MT3 (T5X). Additive only — never overrides measurement (PURPOSE.md invariant #1). Gated on the env var `ASA_ENABLE_MT3=1` for the legacy CLI path and the run-level form field `mt3_mode='enabled'` for the canonical staged API. Driven from `_execute_mt3_attempt`/`_mt3_worker_loop` in `server.py`; emits per-stem MIDI as artifacts and an `mt3` namespace on the run snapshot. Heavy dependencies pinned in `requirements-mt3.txt`. See [`JSON_SCHEMA.md` "Optional MT3 Namespace"](apps/backend/JSON_SCHEMA.md#optional-mt3-namespace).
20. **`live12_catalogue.py` + `phase2_catalogue_gates.py`**: Source-extracted Live 12 catalogue lookup and Phase 2 output-validation gates. `live12_catalogue.py` loads `data/live12_catalogue.json` (generated by `scripts/build_live12_catalogue.py`), validates it against the published schema, and exposes a `Live12Catalogue` API with case-insensitive `has_device`, exact-match parameter lookup, and a `fuzzy_resolve` escape hatch. `phase2_catalogue_gates.py` cross-checks every `{device, parameter, value, phase1Fields}` record in `mixAndMasterChain`, `abletonRecommendations`, and `secretSauce.workflowSteps` against the catalogue and emits **warn-and-keep** `RECOMMENDATION_UNVERIFIED` events on `validationWarnings` (reasons: `device_unknown`, `parameter_unknown`, `value_out_of_range`, `citation_missing`). NEVER drops a recommendation, NEVER rewrites a parameter — an earlier fuzzy-rewrite path produced confidently-wrong output (wrong EQ band + wrong A/B curve), so the contract is now warn-only. Mirrors `_validate_phase2_citation_paths` in spirit. Wired into `server.py` after `_validate_phase2_citation_paths`; load/parse errors degrade to a single skip warning instead of failing the response.
Expand All @@ -299,7 +299,7 @@ Artifact access goes through `artifact_storage.py` rather than direct disk paths

The subprocess isolation means `analyze.py` works as a standalone CLI. Check `apps/backend/JSON_SCHEMA.md` before adding new analyzer output fields. Check `apps/backend/ARCHITECTURE.md` for the full HTTP flow and contract details.

**Phase 2 (`POST /api/phase2`, legacy compat):** Uploads audio to Gemini inline if ≤100 MiB, or via the Gemini Files API if larger. Phase 1 JSON is appended to the system prompt from `prompts/phase2_system.txt`. Also relevant: `prompts/stem_summary_system.txt` and `prompts/live12_device_catalog.json` (the *prompt-injected* device catalogue — distinct from the runtime-validation `data/live12_catalogue.json` consumed by `phase2_catalogue_gates.py`). Backend defense-in-depth: `server_phase2.py`'s `_validate_phase2_citation_paths` mirrors the frontend citation-existence check and emits `validationWarnings` when a recommendation cites a Phase 1 path that doesn't exist — it flags invented citations rather than failing, since Phase 1 stays authoritative (invariant #1). `phase2_catalogue_gates.apply_live12_catalogue_gates` runs immediately after for source-catalogue checks (see backend file #20 above).
**Phase 2 (`POST /api/phase2`, legacy compat):** Uploads audio to Gemini inline if ≤100 MiB, or via the Gemini Files API if larger. Phase 1 JSON is appended to the system prompt from `prompts/phase2_system.txt`. Also relevant: `prompts/stem_summary_system.txt` and `prompts/live12_device_catalog.json` (the *prompt-injected* device catalogue — distinct from the runtime-validation `data/live12_catalogue.json` consumed by `phase2_catalogue_gates.py`). Backend defense-in-depth: `server_phase2.py`'s `_validate_phase2_citation_paths` mirrors the frontend citation-existence check and emits `validationWarnings` when a recommendation cites a Phase 1 path that doesn't exist — it flags invented citations rather than failing, since Phase 1 stays authoritative (invariant #1). `phase2_catalogue_gates.apply_live12_catalogue_gates` runs immediately after for source-catalogue checks (see backend file #20 above). Additional regression gates: `tests/test_phase2_grammar_fix.py` locks in the gerund-fix post-process in `server_phase2.py`; `tests/test_phase2_prompt_catalog.py` pins prompt examples against the Live 12 catalogue.

**Python version constraint:** Python 3.11.x required on macOS arm64. Essentia 2.1b6 wheels are only published for 3.11; this constraint may be relaxable if Essentia publishes 3.12+ wheels.

Expand Down
15 changes: 13 additions & 2 deletions apps/backend/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,10 @@ python3.11 -m venv venv
- `live12_catalogue.py`: Source-extracted Live 12 device/parameter catalogue loader. Reads `data/live12_catalogue.json` (generated by repo-root `scripts/build_live12_catalogue.py` from upstream `gluon/AbletonLive12_MIDIRemoteScripts`), validates against the published schema, and exposes `Live12Catalogue.has_device` (case-insensitive), exact-match parameter lookup, and `fuzzy_resolve`. Static-source extraction carries no `type/min/max/unit/default`; reserved for future runtime-introspection enrichment. Imported by `phase2_catalogue_gates.py` and the catalogue tests.
- `loudness_backend.py`: Selectable Phase 1 loudness backend (default-off experiment, WS3b). `ASA_LOUDNESS_BACKEND=wasm` overrides the four integrated/range/momentary-max/short-term-max LUFS scalars with readings from the native `measure-cli` binary (source-identical to `packages/loudness-spectro-wasm`). `truePeak` and `lufsCurve` stay on Essentia. Any failure degrades back to Essentia silently. Default is `essentia` (no-op). Covered by `tests/test_loudness_backend.py`.
- `separation_backend.py`: Selectable Phase 1 stem-separation backend (default-off experiment). `ASA_SEPARATION_BACKEND=msst` swaps torchaudio Hybrid Demucs for MSST/BS-RoFormer from a `SUC-DriverOld/MSST-WebUI` checkout, keeping the `{stem_name: wav_path}` contract (`vocals/bass/drums/other`, 44.1 kHz) unchanged. MSST runs in its own venv via `scripts/msst_separate_runner.py` subprocess under `ASA_MSST_PYTHON`; any failure degrades back to Demucs silently. Default is `demucs` (no-op). See `separation_ab.py` for the research-only A/B harness. Covered by `tests/test_separation_backend.py`.
- `separation_ab.py`: Research-only A/B harness for comparing Demucs and MSST separation backends on quality (SI-SDR) and runtime. Driven by `scripts/ab_separation_backends.py`. Deleting this file restores the product exactly.
- `separation_ab.py`: Research-only A/B harness for comparing Demucs and MSST separation backends on quality (SI-SDR) and runtime. Driven by `scripts/ab_separation_backends.py`. Deleting this file restores the product exactly. Covered by `tests/test_separation_ab.py`.
- `phase2_provider.py` + `moss_sidecar/`: Selectable Phase 2 interpretation provider (default-off experiment). `ASA_PHASE2_PROVIDER=moss` routes the producer_summary to a self-hosted MOSS-Audio sidecar instead of Gemini; both paths run through the same parse/citation/catalogue validators. The real-model path is a 501 licence-gated stub — research-only. See `docs/PHASE2_PROVIDER.md`. Covered by `tests/test_phase2_provider.py`.
- `phase2_catalogue_gates.py`: **Warn-and-keep** Live 12 source-catalogue annotation of Phase 2 recommendations. Cross-checks every `{device, parameter, value, phase1Fields}` record against `Live12Catalogue` and emits `RECOMMENDATION_UNVERIFIED` events on `validationWarnings` for `device_unknown`, `parameter_unknown`, `value_out_of_range`, `citation_missing`. NEVER drops or rewrites — an earlier fuzzy-rewrite path produced confidently-wrong output (wrong EQ band + wrong A/B curve), so the contract is warn-only. Wired into `server.py` after `_validate_phase2_citation_paths`. Lives separately from `server_phase2.py` so unit tests can run without the FastAPI/pydantic import chain.
- `utils/cleanup.py`: Periodic artifact cleanup helpers used by the server background-task loop.
- `utils/cleanup.py`: Periodic artifact cleanup helpers used by the server background-task loop. Covered by `tests/test_cleanup.py`.
- `tests/test_server.py`: OpenAPI and envelope contract tests.
- `tests/test_analyze.py`: generated WAV fixture, `EXPECTED_TOP_LEVEL_KEYS` snapshot, raw payload assertions.
- `tests/test_csv_export.py`, `tests/test_sample_*.py`, `tests/test_server_samples.py`: Coverage for CSV export and Phase 3 audition samples.
Expand All @@ -158,6 +158,17 @@ python3.11 -m venv venv
- `tests/test_live12_catalogue.py`, `tests/test_phase2_validator_catalogue.py`, `tests/test_phase2_citation_paths.py`: catalogue lookup and Phase 2 warn-and-keep gate behavior.
- `tests/test_spectral_viz.py`, `tests/test_transcription_backends.py`: spectral-artifact and transcription-backend contracts.
- `tests/test_phase1_evaluation.py`, `tests/test_polyphonic_evaluation.py`, `tests/test_recommendation_evaluation.py`: unit coverage for research/eval-only harnesses (mirror their production counterparts).
- `tests/test_phase1_evaluation_transcription.py`: pure-function tests for the Layer 2 transcription evaluation harness path in `phase1_evaluation.py` (no torchcrepe model load required).
- `tests/test_audio_fixture.py`: WAV-fixture helper used by tests that need a deterministic audio file without running the full CLI; carries a copy of `EXPECTED_TOP_LEVEL_KEYS` for structural assertions.
- `tests/test_audio_fixture_smoke.py`: deterministic 440 Hz sine wave generation and basic audio-I/O smoke (no model load required).
- `tests/test_bootstrap_scripts.py`: unit coverage for `bin/asa` install / bootstrap / cleanup script contracts.
- `tests/test_cleanup.py`: unit coverage for `utils/cleanup.py` artifact-cleanup helpers.
- `tests/test_genre_check.py`: unit coverage for `scripts/genre_check.py`.
- `tests/test_phase2_grammar_fix.py`: regression tests for the Phase 2 gerund-fix post-process in `server_phase2.py` (audit-final round fix).
- `tests/test_phase2_prompt_catalog.py`: regression tests for Phase 2 prompt examples against the Live 12 catalogue (`prompts/live12_device_catalog.json`).
- `tests/test_root_dev_script.py`: unit coverage for root `scripts/dev.sh` env-loading behavior.
- `tests/test_root_e2e_script.py`: unit coverage for root `scripts/test-e2e.sh` / `scripts/test-e2e-integration.sh` script contracts.
- `tests/test_separation_ab.py`: focused tests for `separation_ab.py` SI-SDR aggregation math and MUSDB-style on-disk loader.
- `ARCHITECTURE.md`: backend responsibilities and request flow.
- `JSON_SCHEMA.md`: raw CLI schema plus HTTP mapping notes.

Expand Down
Loading
Loading