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
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ npm run verify # lint + test:unit + build + test:smoke (ful
npm run lint # TypeScript type-check only (no ESLint/Prettier)
npm test # All Vitest tests (vitest.config.ts include: tests/**/*.test.ts)
npm run test:unit # Vitest, restricted to tests/services/ (the unit subset)
npx playwright install chromium # first-time Playwright setup (run once from apps/ui/)
npm run test:smoke # Playwright smoke suite (tests/smoke/, default config)
npm run test:smoke:live-gemini # Playwright smoke against the real Gemini Files API (tests/smoke/upload-phase2-live-gemini.spec.ts)
npm run test:e2e # Playwright full e2e suite (playwright.full.config.ts)
Expand Down Expand Up @@ -186,7 +187,7 @@ Operational and one-shot scripts live in two places. They are not on the request
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.
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. Invocation: `scripts/build_live12_catalogue.py --source /path/to/gluon/AbletonLive12_MIDIRemoteScripts --output data/live12_catalogue.json` (or set `SONIC_ANALYZER_LIVE12_SOURCE` env var to omit `--source`).

`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. `bin/asa` script contracts (install, bootstrap, cleanup) are covered by `apps/backend/tests/test_bootstrap_scripts.py`.
Expand Down Expand Up @@ -271,7 +272,7 @@ Artifact access goes through `artifact_storage.py` rather than direct disk paths
1. **`analyze.py`**: Pure DSP pipeline entry point. Runs as a subprocess invoked by `server.py`. Coordinates the split feature modules below. **Writes JSON to stdout, diagnostics to stderr** — this contract is load-bearing.
2. **`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. Loadouts: BPM/key/LUFS/stereo/spectral balance, rhythm/melody detail, segment boundaries, transcription. `analyze_fast.py` is the streamlined pipeline used by `--fast`.
3. **`server.py`**: FastAPI app and router composition. Routes are organized into `server_phase1.py`, `server_phase2.py`, `server_upload.py`, `server_samples.py`. Handles multipart uploads, invokes `analyze.py` (or worker), normalizes raw output into the `phase1` HTTP contract.
4. **`analysis_runtime.py`**: SQLite-backed run state and stage queue management. Run state in `.runtime/analysis_runs.sqlite3`; artifacts in `.runtime/artifacts/`.
4. **`analysis_runtime.py`**: SQLite-backed run state and stage queue management. Run state in `.runtime/analysis_runs.sqlite3`; artifacts in `.runtime/artifacts/`. New artifact-producing code calls `record_artifact` — do not write `.runtime/` paths directly (see also Tripwire #6 and `artifact_storage.py`).
5. **`worker.py`**: Dedicated worker-process entry point for hosted-style background stage execution. In `local` profile, work runs in-process; in `hosted` profile, this is the worker role.
6. **`runtime_profile.py`**: Switchboard for `local` vs `hosted` profile and `all` vs `api` vs `worker` process roles (env: `SONIC_ANALYZER_RUNTIME_PROFILE`, `SONIC_ANALYZER_PROCESS_ROLE`).
7. **`artifact_storage.py`**: Storage-service boundary. Today writes to local disk; the interface is designed so callers do not assume disk paths forever.
Expand Down Expand Up @@ -394,7 +395,7 @@ Things that look like normal code changes but silently break the contract. Most
1. **`print(...)` in [analyze.py](apps/backend/analyze.py) without `file=sys.stderr`.** Stdout is the JSON contract. Any stray print corrupts it and the server reports a parse error with no useful trace. The existing code is consistent about this — match the pattern (`print(f"[warn] ...", file=sys.stderr)`).
2. **Calling `analyze.py` as a subprocess without `--yes`.** The CLI prompts for confirmation when stdin is a TTY. Subprocess invocations must pass `--yes` or hang waiting for input. `server.py` already does; new callers must too.
3. **Renaming a field on only one side.** Python emits *camelCase* JSON directly (`bpmConfidence`, not `bpm_confidence`) — there is no conversion layer. A rename in [analyze.py](apps/backend/analyze.py) without a matching update in [src/types.ts](apps/ui/src/types.ts) is undetectable by either type system; the field just disappears from the UI.
4. **Adding a top-level key without updating `EXPECTED_TOP_LEVEL_KEYS`.** [tests/test_analyze.py](apps/backend/tests/test_analyze.py) holds a snapshot of every root key. New fields require updating that set *and* [JSON_SCHEMA.md](apps/backend/JSON_SCHEMA.md). The same test enforces that `--fast` only populates `FAST_MODE_POPULATED_FIELDS`. A change to *measured values* (not just keys) can also trip the golden-snapshot regression gate in [tests/test_phase1_golden.py](apps/backend/tests/test_phase1_golden.py) (fixture `tests/fixtures/golden/phase1_default.json`) — re-baseline it deliberately, never blindly.
4. **Adding a top-level key without updating `EXPECTED_TOP_LEVEL_KEYS`.** [tests/test_analyze.py](apps/backend/tests/test_analyze.py) holds a snapshot of every root key. New fields require updating that set *and* [JSON_SCHEMA.md](apps/backend/JSON_SCHEMA.md). The same test enforces that `--fast` only populates `FAST_MODE_POPULATED_FIELDS`. A change to *measured values* (not just keys) can also trip the golden-snapshot regression gate in [tests/test_phase1_golden.py](apps/backend/tests/test_phase1_golden.py) (fixture `tests/fixtures/golden/phase1_default.json`) — re-baseline it deliberately, never blindly (from `apps/backend/`): `UPDATE_PHASE1_GOLDEN=1 ./venv/bin/python -m unittest tests.test_phase1_golden`
5. **Using `document` or `window` in `tests/services/`.** Vitest runs in `node`, not `jsdom`. Service-layer tests are pure logic; if you need DOM, it's a Playwright test in `tests/smoke/` instead.
6. **Hard-coding `Path(...)` for artifacts in new code.** Artifact access must go through [artifact_storage.py](apps/backend/artifact_storage.py). Direct paths work in `local` profile and break silently in `hosted`.
7. **Editing `apps/ui/.env` and expecting `dev.sh` to honor it.** `dev.sh` reads `apps/ui/.env` but *overrides* `VITE_API_BASE_URL` for the spawned UI process so stale `.env` files don't break the stack. To point the UI at a non-canonical backend, edit `dev.sh` or run the UI directly with the env var on the command line.
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ python3.11 -m venv venv
- Run one test module:

```bash
./venv/bin/python -m unittest tests/test_server.py
./venv/bin/python -m unittest tests/test_analyze.py
./venv/bin/python -m unittest tests.test_server
./venv/bin/python -m unittest tests.test_analyze
```

- Run one test class:
Expand Down
2 changes: 1 addition & 1 deletion apps/ui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

## Environment And Setup

- Use Node 20+.
- Use Node 20 (per CI; no `engines` constraint in `package.json`).
- Install dependencies: `npm install`
- Create a local env file when needed: `cp .env.example .env`
- Key env vars:
Expand Down
Loading