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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to `asa` are documented here.
## Unreleased

### Added
- **Phase 3 audition samples** (`POST/GET /api/analysis-runs/{run_id}/samples`): on-demand heuristic WAV/MIDI clips derived from Phase 1 measurements (and Phase 2 context when available), with a citation manifest. PyTheory generates the musical plan, FluidSynth (with sine-additive fallback) renders audio, NumPy synthesizes drum one-shots. Not part of the staged-execution queue. See [`docs/SAMPLE_GENERATION.md`](docs/SAMPLE_GENERATION.md).
- **URL-mode ingestion** for `POST /api/analysis-runs`: provide a public `http`/`https` `url` form field instead of a multipart `track`. SSRF-guarded against private/loopback/link-local addresses; streams through the shared 100 MiB cap. See [`apps/backend/url_ingest.py`](apps/backend/url_ingest.py).
- **Operator `X-Admin-Key` DELETE bypass** for `DELETE /api/analysis-runs/{run_id}`: when `SONIC_ANALYZER_ADMIN_KEY` is set, operators can purge any run; otherwise owner-only deletes apply. Admin path is closed by default.
- **`GET /api/analysis-runs/{run_id}/source-audio`**: owner-only re-serve of the originally ingested audio (no admin bypass). Saves a round-trip vs looking up the source artifact id.
- **CSV export** of Phase 1 time-series fields: `GET /api/analysis-runs/{run_id}/export/csv/{field_path}`, backed by the registry in [`apps/backend/csv_export.py`](apps/backend/csv_export.py). Schema record: [`docs/adr/0001-phase1-json-schema-v1.md`](docs/adr/0001-phase1-json-schema-v1.md).
- **Additive `publicStatus` field** on every stage in the run snapshot — collapses the eight internal stage statuses into a five-value client-facing vocabulary (`queued`, `running`, `completed`, `failed`, `interrupted`, plus `null` for `not_requested`). See [`apps/backend/stage_status.py`](apps/backend/stage_status.py).
- **Reassigned spectrogram** as an opt-in spectral enhancement (`POST /api/analysis-runs/{run_id}/spectral-enhancements/reassigned`): sharper transient/frequency localization via `librosa.reassigned_spectrogram`. Joins existing `cqt`, `hpss`, `onset`, `chroma_interactive`.
- **Chain-of-custody audit pass**: recommendations-first information architecture, applied-recommendations tracker, and grammar post-process on Phase 2 output. New components: [`CitationBlock.tsx`](apps/ui/src/components/CitationBlock.tsx), [`appliedRecommendations.ts`](apps/ui/src/services/appliedRecommendations.ts).
- **Stem summary interpretation** (Experiment B): Gemini stem listening via Structured Outputs on separated bass and musical stems, producing bar-aligned musical descriptions with scale degrees, rhythmic patterns, and uncertainty flags
- Backend: stem files persist as run artifacts during pitch/note work; `stem_summary` profile runs against persisted `stem_bass` and `stem_other` audio; per-stem Gemini outputs combined into one product-facing result
- Frontend: polling loop auto-queues `stem_summary` after pitch/note translation completes; renders separate "AI stem summary" section alongside Session Musician draft notes
Expand All @@ -24,6 +32,9 @@ All notable changes to `asa` are documented here.
- Dense techno boundary regression test (145 BPM)

### Changed
- **Backend monolith split** into domain modules (commit `5c40dd44`): `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`. Server routes likewise split into `server_phase1.py`, `server_phase2.py`, `server_upload.py`, `server_samples.py`.
- **`BatchedBandpass` centralization** ([`apps/backend/dsp_bandbank.py`](apps/backend/dsp_bandbank.py)): per-band 4th-order Butterworth filtering with zero-phase `filtfilt` now lives in one place instead of being duplicated across detectors.
- **Hosted runtime foundation** landed without disturbing local mode: [`runtime_profile.py`](apps/backend/runtime_profile.py), [`worker.py`](apps/backend/worker.py), [`artifact_storage.py`](apps/backend/artifact_storage.py), [`auth_context.py`](apps/backend/auth_context.py). See [`docs/PUBLIC_HOSTING_FOUNDATION.md`](docs/PUBLIC_HOSTING_FOUNDATION.md).
- Synthesis character labels aligned to phase2 prompt thresholds (three-tier: clean subtractive / FM-acid / wavetable-noise)
- Removed citation instructions from Phase 2 system prompt (citations added noise, not value)
- `dynamicCharacter` forwarded through `_build_phase1()` to Gemini Phase 2
Expand Down
23 changes: 15 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ npm run test:smoke -- tests/smoke/upload-phase1.spec.ts
```bash
./apps/backend/scripts/bootstrap.sh # Create/recreate venv (Python 3.11.x required)
./apps/backend/venv/bin/python apps/backend/server.py # FastAPI server on 8100
./apps/backend/venv/bin/python apps/backend/analyze.py <file> [--separate] [--transcribe] [--fast] [--yes]
./apps/backend/venv/bin/python apps/backend/analyze.py <file> [--separate] [--transcribe] [--fast] [--standard] [--yes] [--pitch-note-only] [--stem-dir DIR] [--stem-output-dir DIR] [--pitch-note-backend BACKEND]

# All backend tests (run from apps/backend/)
./venv/bin/python -m unittest discover -s tests
Expand Down Expand Up @@ -156,17 +156,24 @@ The subprocess isolation means `analyze.py` works as a standalone CLI. Check `ap

Single-page React 19 + Vite + TypeScript + Tailwind CSS v4 app with no router. View states managed via React conditionals (upload → estimate → analysis → results). Vitest for unit tests, Playwright for smoke tests.

**Key service files:**
**Key service files** (canonical transport + chain-of-custody contracts):

1. **`src/services/analysisRunsClient.ts`**: Canonical transport. Creates runs against `/api/analysis-runs`, polls snapshots, fetches pitch/note translations and interpretations.
2. **`src/services/analyzer.ts`**: Phase orchestration entry point — sequences run creation, polling, and display payload projection.
3. **`src/services/backendPhase1Client.ts`**: Legacy multipart transport (typed error classes, `AbortController` timeouts, identity probe via `/openapi.json`). Kept for the compatibility wrappers; new flows should go through `analysisRunsClient.ts`.
4. **`src/services/spectralArtifactsClient.ts`**: Fetches spectrogram/spectral-evolution artifacts via `/api/analysis-runs/{run_id}/artifacts/…`.
5. **`src/services/mixDoctor.ts`**: Mix advisory logic — client-side scoring and suggestions against measured spectral balance.
6. **`src/services/phase2Validator.ts`**: Runtime guardrail. Validates Phase 2 consistency against Phase 1 (`validateBPMConsistency`, `validateKeyConsistency`, `validateLUFSConsistency`, `validateGenreDSPConsistency`, `validateNumericBounds`).
7. **`src/services/midi/`**: MIDI export, preview, and quantization utilities (`midiExport.ts`, `midiPreview.ts`, `quantization.ts`).
8. **`src/types.ts`** + **`src/types/`**: `types.ts` is a barrel re-export of `./types/{measurement,interpretation,backend}.ts`. `Phase1Result` lives in `types/measurement.ts`; `AnalysisRunSnapshot` in `types/backend.ts`; `Phase2Result` in `types/interpretation.ts`.
9. **`src/config.ts`**: Runtime resolution of `VITE_API_BASE_URL` and feature flags; falls back to `http://127.0.0.1:8100`. Supports window-level overrides (`window.__VITE_API_BASE_URL_OVERRIDE__`, `window.__VITE_ENABLE_PHASE2_GEMINI_OVERRIDE__`) for hosted deployments that inject config at runtime without a rebuild.
4. **`src/services/httpClient.ts`**: Shared fetch helpers and request-header injection used by the run/artifact/sample clients.
5. **`src/services/spectralArtifactsClient.ts`**: Fetches spectrogram/spectral-evolution artifacts via `/api/analysis-runs/{run_id}/artifacts/…`.
6. **`src/services/sampleGenerationClient.ts`**: Phase 3 audition-sample POST/GET against `/api/analysis-runs/{run_id}/samples`, plus per-clip artifact streaming.
7. **`src/services/mixDoctor.ts`**: Mix advisory logic — client-side scoring and suggestions against measured spectral balance.
8. **`src/services/phase2Validator.ts`**: Runtime guardrail. Validates Phase 2 consistency against Phase 1 (`validateBPMConsistency`, `validateKeyConsistency`, `validateLUFSConsistency`, `validateGenreDSPConsistency`, `validateNumericBounds`).
9. **`src/services/appliedRecommendations.ts`** + **`userLabels.ts`**: Applied-recommendations tracker and persisted-label state used by the audit overhaul.
10. **`src/services/phase1Picker.ts`** + **`phaseLabels.ts`**: Phase-snapshot projection helpers consumed by the results surface.
11. **`src/services/audioFile.ts`**: Client-side audio validation, blank-MIME extension fallback, preview-URL lifecycle.
12. **`src/services/fieldAnalytics.ts`** + **`diagnosticLogs.ts`**: Instrumentation hooks and diagnostic-log capture for the request panel.
13. **`src/services/midi/`**: MIDI export, preview, and quantization utilities (`midiExport.ts`, `midiPreview.ts`, `quantization.ts`).
14. **`src/services/sessionMusician/`**: Session Musician helpers — `confidenceBand.ts`, `noteConversion.ts`, `renderState.ts`, `stemListeningNotes.ts`.
15. **`src/types.ts`** + **`src/types/`**: `types.ts` is a barrel re-export of `./types/{measurement,interpretation,backend}.ts`. `Phase1Result` lives in `types/measurement.ts`; `AnalysisRunSnapshot` in `types/backend.ts`; `Phase2Result` in `types/interpretation.ts`; `./types/samples.ts` is imported directly, not through the barrel.
16. **`src/config.ts`**: Runtime resolution of `VITE_API_BASE_URL` and feature flags; falls back to `http://127.0.0.1:8100`. Supports window-level overrides (`window.__VITE_API_BASE_URL_OVERRIDE__`, `window.__VITE_ENABLE_PHASE2_GEMINI_OVERRIDE__`) for hosted deployments that inject config at runtime without a rebuild.

`AnalysisResults.tsx` is the large results surface, lazy-loaded via Suspense. Manual vendor chunks in `vite.config.ts` control bundle splitting.

Expand Down
3 changes: 2 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-05-15.
- There are no repo-local Cursor rules, `.cursorrules`, or Copilot instruction files in this repo as of 2026-05-17.

## Working Style For Agents

Expand Down Expand Up @@ -121,6 +121,7 @@ python3.11 -m venv venv
- `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 part of the shipped product path.
- `utils/cleanup.py`: Periodic artifact cleanup helpers used by the server background-task loop.
- `symbolic_extract.py`: **Orphaned and broken.** Earlier worker-process entry point for pitch/note translation; superseded by `analyze.py --pitch-note-only`. Still imports a removed `BasicPitchBackend` symbol from `analyze.py`, so loading the module would raise `ImportError`. Not referenced from any other module. Slated for removal — do not extend it.
- `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 Down
1 change: 1 addition & 0 deletions apps/backend/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
| `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. |
| `utils/cleanup.py` | Periodic artifact cleanup helpers used by the server background-task loop. |
| `symbolic_extract.py` | **Orphaned.** Earlier worker-process entry point for pitch/note translation; superseded by `analyze.py --pitch-note-only`. Currently imports a removed `BasicPitchBackend` and would fail at module load. Not invoked from anywhere else in the tree; slated for removal. |
| `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. |
Expand Down
13 changes: 12 additions & 1 deletion apps/ui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- 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. 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.
- No repo-local `.cursorrules`, `.cursor/rules/`, or `.github/copilot-instructions.md` exist here as of 2026-05-17.

## Working Style For Agents

Expand Down Expand Up @@ -91,6 +91,17 @@ RUN_GEMINI_LIVE_SMOKE=true VITE_ENABLE_PHASE2_GEMINI=true GEMINI_API_KEY=your_ke
- `src/services/analysisRunsClient.ts`: canonical transport — creates runs against `/api/analysis-runs`, polls stage snapshots, fetches pitch/note translations and interpretations.
- `src/services/backendPhase1Client.ts`: legacy multipart transport (typed errors, `AbortController` timeouts). Kept only for the compatibility wrappers; new flows go through `analysisRunsClient.ts`.
- `src/services/analyzer.ts`: phase orchestration — sequences run creation, polling, and display payload projection.
- `src/services/httpClient.ts`: shared fetch helpers and request-header injection used by the run/artifact/sample clients.
- `src/services/spectralArtifactsClient.ts`: spectrogram and spectral-evolution artifact fetches via `/api/analysis-runs/{run_id}/artifacts/…`.
- `src/services/sampleGenerationClient.ts`: Phase 3 audition-sample POST/GET against `/api/analysis-runs/{run_id}/samples` plus per-clip artifact streaming.
- `src/services/audioFile.ts`: client-side audio validation, blank-MIME extension fallback, and preview-URL lifecycle.
- `src/services/mixDoctor.ts`: client-side spectral-balance scoring against genre profiles.
- `src/services/phase2Validator.ts`: runtime guardrail — chain-of-custody checks of Phase 2 against Phase 1 (BPM, key, LUFS, genre/DSP, numeric bounds).
- `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/types.ts` + `src/types/`: shared frontend contract types. `types.ts` is a barrel re-export of `./types/{measurement,interpretation,backend}.ts`; `./types/samples.ts` exists but is imported directly, not through the barrel.
- `src/index.css`: Tailwind theme tokens and visual language.
- `tests/services/*`: unit and service tests.
Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE_STRATEGY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ASA Architecture Strategy

**Last updated:** March 2026
**Last updated:** May 2026 (Phase 3 audition samples shipped; CSV export, URL ingest, admin DELETE, source-audio route, `publicStatus`, and reassigned spectrogram landed in the same window — no shifts to the three-layer thesis or library decisions below)
**Status:** Living document — update when experiments produce results or the AI capability landscape shifts materially.
**Sources:** ChatGPT o3 deep research (March 2026), Codex architecture hardening audit, Perplexity ecosystem research (Demucs/separation alternatives), session analysis with Claude Sonnet, and the 2026-03-18 reality audit ([archived](archive/stage3-reality-audit-2026-03-18.md)). The three `deep-research-report*.md` files originally cited here were external research inputs and are not committed to this repo.

Expand Down
13 changes: 2 additions & 11 deletions docs/SAMPLE_GENERATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,18 +182,9 @@ This keeps audition WAV/MIDI access on the same code path as every other run-sco

### Snapshot integration

`AnalysisRunSnapshot.stages.sampleGeneration` becomes:
Sample generation is **not** a stage on `AnalysisRunSnapshot.stages` — the snapshot still tracks the three queued stages only (`measurement`, `pitchNoteTranslation`, `interpretation`). Audition samples ride on the existing `run_artifacts` table with `kind` values `sample_audio`, `sample_midi`, and `sample_manifest`, and the manifest itself is fetched directly via `GET /api/analysis-runs/{run_id}/samples` (404 when not yet generated).

```ts
{
status: "not_requested" | "completed" | "failed",
manifestSampleCount?: number,
generatedAt?: string,
synthesisBackend?: "fluidsynth" | "sine_fallback"
}
```

`not_requested` is the default — the stage is opt-in, not auto-enqueued. This is intentional: until audition value is validated, we don't want to pay the synthesis cost on every run.
The synthesis backend used and the generated-at timestamp are recorded on the manifest body, not on the snapshot. Promotion to a first-class stage with `publicStatus` tracking is a follow-up if audition value pans out.

## Dependencies

Expand Down
1 change: 0 additions & 1 deletion docs/history/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ 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.