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: 15 additions & 1 deletion apps/backend/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- The repo is a local Python audio-analysis service with two entry points:
- `analyze.py`: raw CLI analyzer
- `server.py`: FastAPI wrapper around the CLI
- There are no repo-local Cursor rules, `.cursorrules`, or Copilot instruction files in this repo as of 2026-03-10.
- There are no repo-local Cursor rules, `.cursorrules`, or Copilot instruction files in this repo as of 2026-05-15.

## Working Style For Agents

Expand Down Expand Up @@ -110,7 +110,9 @@ python3.11 -m venv venv
- `analyze_core.py`, `analyze_audio_io.py`, `analyze_detection.py`, `analyze_estimate.py`, `analyze_rhythm.py`, `analyze_segments.py`, `analyze_structure.py`, `analyze_transcription.py`, `analyze_fast.py`: Feature modules (BPM/key/LUFS/stereo, rhythm/melody/groove, segments, structure, transcription, the `--fast` pipeline). Split from the original monolith in commit `5c40dd44` — keep the split when adding features.
- `server.py` + `server_phase1.py`, `server_phase2.py`, `server_upload.py`, `server_samples.py`: FastAPI app + route modules. Multipart/URL upload handling, subprocess execution, envelope normalization, and the on-demand Phase 3 audition-sample routes.
- `analysis_runtime.py`: SQLite-backed run state, stage queue, artifact metadata.
- `stage_status.py`: Stage-status helpers, including the `publicStatus` projection used by the snapshot API.
- `worker.py`, `runtime_profile.py`, `auth_context.py`, `artifact_storage.py`: Hosted-mode foundation. Local mode shouldn't branch through these unless it has to.
- `url_ingest.py`: SSRF-guarded URL ingestion for `POST /api/analysis-runs`.
- `upload_limits.py`: Canonical 100 MiB raw-audio / 101 MiB request-envelope limits. Operator contract is generated, not hand-edited.
- `url_ingest.py`: SSRF-guarded URL-mode ingestion for `POST /api/analysis-runs`.
- `csv_export.py`: CSV exporters for Phase 1 time-series fields; backs `GET /api/analysis-runs/{run_id}/export/csv/{field_path}`.
Expand All @@ -120,11 +122,23 @@ python3.11 -m venv venv
- `spectral_viz.py`: Librosa spectrogram and spectral time-series artifacts. Non-critical — failures don't break a run.
- `phase1_evaluation.py` + `phase1_report_html.py`: Offline Phase 1 evaluation harness and HTML render. Not on the product path; driven by `scripts/evaluate_phase1.py`.
- `polyphonic_evaluation.py` + `scripts/evaluate_polyphonic.py`: **Research-only.** Offline polyphonic-transcription evaluation harness, not part of the shipped product path.
- `phase1_evaluation.py`, `phase1_report_html.py`: Offline evaluation harness for Phase 1 measurement quality. Research-only.
- `utils/cleanup.py`: Periodic artifact cleanup helpers used by the server background-task loop.
- `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.
- `ARCHITECTURE.md`: backend responsibilities and request flow.
- `JSON_SCHEMA.md`: raw CLI schema plus HTTP mapping notes.

## Operator and Research Scripts

Under `apps/backend/scripts/` (not on the product path):

- `bootstrap.sh`: create/recreate the venv with the pinned Python 3.11 dependencies.
- `dev.sh`: backend-only dev launcher used by the monorepo `./scripts/dev.sh`.
- `render_upload_limit_contract.py`: re-renders the operator-facing upload-limit contract whenever `upload_limits.py` numbers change.
- `evaluate_phase1.py`, `evaluate_structure_sweep.py`, `evaluate_polyphonic.py`, `genre_check.py`, `audit_pass1.py`, `replay_catalog_validation.py`: research and audit harnesses for measurement quality and prompt-output review. Outputs land under `.runtime/reports/` and are intentionally not wired into the live API.

## Code Style

- Follow the surrounding file style instead of introducing a new formatter profile.
Expand Down
7 changes: 7 additions & 0 deletions apps/backend/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
| `analyze.py` | Raw CLI analyzer entry point. Loads audio, coordinates the `analyze_*.py` feature modules (see [Analyzer Submodules](#analyzer-submodules) below), optionally separates stems and transcribes notes through torchcrepe, then prints JSON to `stdout`. |
| `server.py` + `server_phase1.py` / `server_phase2.py` / `server_upload.py` / `server_samples.py` | FastAPI app and router composition. Accepts uploads, computes estimates, manages the canonical staged run API, normalizes measurement results, serves artifact access, and exposes the on-demand Phase 3 audition-sample routes. |
| `analysis_runtime.py` | Run-state persistence and staged-analysis orchestration. Owns run snapshots, stage status, artifact metadata, and ownership checks. |
| `stage_status.py` | Helpers for normalizing stage execution status across the runtime and HTTP surfaces (e.g. `publicStatus` projection). |
| `artifact_storage.py` | Artifact storage boundary. The current implementation uses the local filesystem, but the runtime now talks to a storage service interface instead of assuming every artifact is a local disk path forever. |
| `runtime_profile.py` | Runtime/profile switchboard for `local` vs `hosted` behavior and `all` vs `api` vs `worker` process roles. |
| `auth_context.py` | Hosted-mode user-context resolution. Establishes the current run owner in the canonical API path. |
| `worker.py` | Dedicated worker-process entry point for hosted-style background stage execution. |
| `url_ingest.py` | URL-mode ingestion for `POST /api/analysis-runs`. SSRF-guarded against private/loopback/link-local addresses; streams to enforce the shared 100 MiB cap. |
| `upload_limits.py` | Canonical raw-audio (100 MiB) and request-envelope (101 MiB) limits, plus the protected-route list. Operator contract is generated, not hand-edited — see `scripts/render_upload_limit_contract.py`. |
| `spectral_viz.py` | Librosa-based spectrogram generation and spectral time-series extraction. Produces mel/chroma PNG spectrograms and per-frame spectral evolution JSON. Called after successful measurement; failures are non-critical. |
| `url_ingest.py` | SSRF-guarded URL-mode ingestion for `POST /api/analysis-runs`. Fetches a public `http`/`https` audio file and feeds the bytes through the same downstream pipeline as a multipart upload. |
Expand All @@ -20,9 +22,13 @@
| `dsp_bandbank.py` + `dsp_utils.py` | Shared DSP primitives: `BatchedBandpass` (4th-order Butterworth bandpass bank with zero-phase `filtfilt`) and cross-module utility functions. |
| `phase1_evaluation.py` + `phase1_report_html.py` | Offline Phase 1 evaluation harness — deterministic-metric and detector-stability reporting, with a standalone HTML render. Not on the product path; driven by `scripts/evaluate_phase1.py`. |
| `polyphonic_evaluation.py` + `scripts/evaluate_polyphonic.py` | Research-only offline polyphonic-transcription evaluation harness. Not on the product path. |
| `phase1_evaluation.py` + `phase1_report_html.py` | Offline evaluation harness for Phase 1 measurement quality. Research-only. |
| `utils/cleanup.py` | Periodic artifact cleanup helpers used by the server background-task loop. |
| `tests/test_server.py` | Contract tests for estimate, timeout, and success envelopes. |
| `tests/test_analyze.py` | Structural snapshot tests for the raw analyzer JSON output. Owns `EXPECTED_TOP_LEVEL_KEYS` — update it whenever you add a root field. |
| `tests/test_spectral_viz.py` | Unit tests for spectrogram generation, time-series computation, and artifact orchestration. |
| `tests/test_csv_export.py` | Round-trip CSV-exporter tests against the registry in `csv_export.py`. |
| `tests/test_sample_*.py` + `tests/test_server_samples.py` | Phase 3 audition-sample synthesis and HTTP contract tests. |

### Analyzer Submodules

Expand Down Expand Up @@ -76,6 +82,7 @@ Custom routes:
- `POST /api/analysis-runs/estimate`
- `POST /api/analysis-runs` — multipart upload OR URL ingestion. Provide *exactly one* of `track` (multipart `UploadFile`) or `url` (form field with a public `http`/`https` URL). URL mode is SSRF-guarded against private/loopback/link-local addresses and enforces the same 100 MiB cap via streaming. See [`url_ingest.py`](url_ingest.py).
- `GET /api/analysis-runs/{run_id}`
- `POST /api/analysis-runs/{run_id}/interrupt` — terminate any active child processes for the run and mark stages interrupted.
- `DELETE /api/analysis-runs/{run_id}` — owner can delete their own run; operators with `SONIC_ANALYZER_ADMIN_KEY` set can supply `X-Admin-Key` to delete any run. Admin path is closed when the env var is unset.
- `GET /api/analysis-runs/{run_id}/artifacts` and `…/artifacts/{artifact_id}`
- `GET /api/analysis-runs/{run_id}/source-audio` — re-serves the original ingested audio for the run. Owner-only (no admin bypass). Saves a round-trip vs looking up the source artifact id first.
Expand Down
1 change: 1 addition & 0 deletions apps/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Canonical live-analysis routes:
Legacy compatibility routes:

- `POST /api/analyze` (legacy compatibility wrapper)
- `POST /api/analyze/estimate` (legacy compatibility wrapper)
- `POST /api/phase2` (legacy compatibility wrapper)

FastAPI also serves the usual generated endpoints at `/openapi.json`, `/docs`, and `/redoc`.
Expand Down
9 changes: 5 additions & 4 deletions apps/backend/csv_export.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""CSV exporters for Phase 1 time-series fields.

Patterned on the ``(time, duration, value)`` tabular shape used by Partiels
and similar Vamp-output tools (see ``docs/external-repo-review-2026-05-13.md``
Track 2 for the rationale and the rejected-alternatives discussion). Each
exporter maps one dotted JSON path inside the Phase 1 measurement payload to
a small CSV with documented columns.
and similar Vamp-output tools (see
``docs/history/external-repo-review-2026-05-13.md`` Track 2 for the rationale
and the rejected-alternatives discussion). Each exporter maps one dotted
JSON path inside the Phase 1 measurement payload to a small CSV with
documented columns.

The exporters are kept here, outside ``server.py``, so the route handler can
stay a thin lookup-and-serve.
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/tests/test_loudness_r128.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""EBU R128 verification + regression gate for ASA's loudness path.

Track 1 of the external-repo incorporation plan (docs/external-repo-review-2026-05-13.md)
Track 1 of the external-repo incorporation plan (docs/history/external-repo-review-2026-05-13.md)
asked: is ASA's integrated-LUFS implementation correct, or does it lag the BS.1770-5
revision? This module answers that with the EBU Tech 3341 compliance signals — the
canonical loudness conformance test set — and now also gates the sample-rate
Expand Down Expand Up @@ -160,7 +160,7 @@ class TestLoudnessR128AtNon441kHz(unittest.TestCase):
bug* (sample rate not threaded), not an algorithm bug.

Originally the open finding from the verification spike documented
in docs/external-repo-review-2026-05-13.md (Track 1 follow-up). The
in docs/history/external-repo-review-2026-05-13.md (Track 1 follow-up). The
follow-up fix lives in this branch's companion edits to
``analyze_core.analyze_loudness`` (now takes ``sample_rate``) and
its call sites in ``analyze.py``; the regression test below
Expand Down
5 changes: 3 additions & 2 deletions apps/ui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

- This file applies to `apps/ui` inside the `asa` monorepo.
- Stack: React 19, TypeScript, Vite 6, Tailwind CSS v4, Vitest, Playwright.
- The app talks to the local `sonic-analyzer` backend.
- No repo-local `.cursorrules`, `.cursor/rules/`, or `.github/copilot-instructions.md` exist here as of 2026-03-10.
- The app talks to the local `sonic-analyzer` backend. Gemini is backend-mediated; the UI does **not** import an AI SDK.
- No repo-local `.cursorrules`, `.cursor/rules/`, or `.github/copilot-instructions.md` exist here as of 2026-05-15.

## Working Style For Agents

Expand Down Expand Up @@ -95,6 +95,7 @@ RUN_GEMINI_LIVE_SMOKE=true VITE_ENABLE_PHASE2_GEMINI=true GEMINI_API_KEY=your_ke
- `src/index.css`: Tailwind theme tokens and visual language.
- `tests/services/*`: unit and service tests.
- `tests/smoke/*`: smoke and live smoke coverage.
- `tests/e2e/*`: canonical no-Gemini integration spec plus live full-stack Gemini specs (Playwright).

## Code Style

Expand Down
5 changes: 4 additions & 1 deletion apps/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ The app uploads a track to the local DSP backend, shows the estimate and executi
- Vite 6
- Tailwind CSS v4
- WaveSurfer.js
- Google Gen AI SDK
- MIDI Writer JS
- Vitest
- Playwright

Gemini is backend-mediated: the UI never imports an AI SDK. The backend reads
`GEMINI_API_KEY` at runtime and the UI posts to
`POST /api/analysis-runs/{run_id}/interpretations`.

## Prerequisites

- Node.js 20+
Expand Down
4 changes: 2 additions & 2 deletions docs/adr/0001-phase1-json-schema-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ ASA's HTTP contract has two layers that matter to external consumers:

These two layers share the same field shape — Python emits camelCase JSON directly; there is no rename layer between them ([CLAUDE.md tripwire #3](../../CLAUDE.md)). That coupling has served ASA well, but it carries no explicit version or compatibility promise. Until this ADR, "Phase 1 schema v1" was implicit in `EXPECTED_TOP_LEVEL_KEYS` and `Phase1Result` — provable from code but not stated as a contract.

The external-repo review at [`docs/external-repo-review-2026-05-13.md`](../external-repo-review-2026-05-13.md) flagged this gap as Track 2 work. Partiels exports a documented schema (CSV/JSON/SDIF), and consumers of ASA's output (REAPER scripts, Max patches, downstream pipelines) need a stable shape to write against.
The external-repo review at [`docs/history/external-repo-review-2026-05-13.md`](../history/external-repo-review-2026-05-13.md) flagged this gap as Track 2 work. Partiels exports a documented schema (CSV/JSON/SDIF), and consumers of ASA's output (REAPER scripts, Max patches, downstream pipelines) need a stable shape to write against.

## Decision

Expand Down Expand Up @@ -95,6 +95,6 @@ There is no single "phase1.v1.json" file. The schema is the four-test-suite inte

## Alternatives considered

- **Mirror Partiels' export schema verbatim.** Rejected in [external-repo-review-2026-05-13.md](../external-repo-review-2026-05-13.md). Partiels' CSV is `time, duration, label/value` per Vamp track — too flat for ASA's domain-named measurements. Would have collapsed the citation chain (Quality Invariant #2).
- **Mirror Partiels' export schema verbatim.** Rejected in [external-repo-review-2026-05-13.md](../history/external-repo-review-2026-05-13.md). Partiels' CSV is `time, duration, label/value` per Vamp track — too flat for ASA's domain-named measurements. Would have collapsed the citation chain (Quality Invariant #2).
- **Generate a JSON Schema artifact.** Deferred. No current consumer needs it; the test-snapshot enforcement already prevents drift.
- **Version the schema via HTTP `Accept` header.** Overkill for one runtime. Re-evaluate at v2.
3 changes: 3 additions & 0 deletions docs/history/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ Everything in this directory is past-tense. Treat it as a paper trail, not a sou
- `phase1-hardening-plan.md` — completed Phase 1 hardening plan.
- `library-review-torchfx-2026-05-13.md` — one-shot library evaluation of torchfx against ASA's DSP path.
- `phase1-audit/` — one-shot advisory deliverable: audit, decks, evidence index, visual story pack.
- `library-review-torchfx-2026-05-13.md` — completed library review.
- `external-repo-review-2026-05-13.md` — completed external-repo incorporation review (openmeters / soundscope / Partiels / forever-jukebox). All three tracks resolved.
- `track1-spike-outcome-2026-05-13.md` — completed loudness verification spike. Fix shipped; regression test retained.
- `archive/` — older archived plans and result stubs.
Loading