diff --git a/CLAUDE.md b/CLAUDE.md index bc28af6d..c8859091 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 @@ -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. @@ -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. diff --git a/apps/backend/AGENTS.md b/apps/backend/AGENTS.md index 33799203..5beed8d3 100644 --- a/apps/backend/AGENTS.md +++ b/apps/backend/AGENTS.md @@ -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. @@ -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. diff --git a/apps/ui/AGENTS.md b/apps/ui/AGENTS.md index 6b685fd7..f2ea6c56 100644 --- a/apps/ui/AGENTS.md +++ b/apps/ui/AGENTS.md @@ -109,8 +109,8 @@ RUN_GEMINI_LIVE_SMOKE=true VITE_ENABLE_PHASE2_GEMINI=true GEMINI_API_KEY=your_ke - `src/services/phase1Picker.ts` + `phaseLabels.ts`: phase-snapshot projection helpers used by the results surface. - `src/services/appliedRecommendations.ts` + `userLabels.ts`: applied-recommendations tracker and persisted label state used by the audit overhaul. - `src/services/fieldAnalytics.ts` + `diagnosticLogs.ts`: instrumentation hooks and diagnostic log capture for the request panel. -- `src/services/midi/`: MIDI export, preview, and quantization (`midiExport.ts`, `midiPreview.ts`, `quantization.ts`). -- `src/services/sessionMusician/`: Session Musician helpers — `confidenceBand.ts`, `noteConversion.ts`, `renderState.ts`, `stemListeningNotes.ts`. +- `src/services/midi/`: MIDI export, preview, and quantization (`midiExport.ts`, `midiPreview.ts`, `quantization.ts`, `types.ts`). +- `src/services/sessionMusician/`: Session Musician helpers — `confidenceBand.ts`, `index.ts`, `noteConversion.ts`, `renderState.ts`, `stemListeningNotes.ts`. - `src/data/genreProfiles.ts`: genre profile definitions consumed by `mixDoctor.ts` for spectral-balance scoring and recommendations. - `src/types.ts` + `src/types/`: shared frontend contract types. `types.ts` re-exports through `./types/index.ts`, which re-exports `measurement.ts`, `interpretation.ts`, and `backend.ts`. `./types/samples.ts` exists but is imported directly, not through the barrel. - `src/hooks/`: custom React hooks — `useCpuMeter.ts`, `useGlobalDrag.ts`, `useImageZoom.ts`, `useSpectralCursorBus.tsx`.