# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Purpose

This Lambda downloads a sound recording asset from S3, generates an ACRCloud audio fingerprint from it, uploads that fingerprint to ACRCloud's deduplication API, and writes the resulting `acr_id` back to OWS (ows-sound-recordings). It is invoked directly (not via Kafka) with a JSON event containing `asset.id`, `asset.filename`, and `asset.extension`.

## Development Commands

See the repo-root `CLAUDE.md` for the full Docker Compose workflow. From this directory:

```bash
# Run tests and linting
docker compose up --build lint-and-test

# Run a single test by name
TEST_ARGS="-k test_create_fingerprint" docker compose up --build lint-and-test

# Skip linting
SKIP_LINT=true docker compose up --build lint-and-test

# Start the function locally
docker compose up --build -d function
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d @tests/sample_event.json

# Quick local invocation without Docker (requires local deps + .env)
python simulate_event.py
```

## Local Setup

```bash
cp .env.shadow .env
# Fill in ACR_CLOUD_ACCESS_TOKEN (JWT from ACRCloud Console, see README.md)
# Fill in SENTRY_DSN if needed
```

AWS credentials are mounted from `~/.aws/credentials` via `docker-compose.yaml` using `AWS_PROFILE=dev`. Use `awsume` to activate the correct profile first.

Test audio assets must exist in S3 at `dev-orcd-raw-assets/fingerprinting/acrcloud/<filename>.<ext>`. Sample files (`my_song_1.mp3`, `my_song_2.wav`) from the ACRCloud docs are checked into `tests/fixtures/` for unit tests.

## Architecture

**Event flow:**
1. `handler` in `src/app.py` receives `{asset: {id, filename, extension}}`
2. `s3_assets.download_asset(filename, extension)` fetches raw bytes from `{env}-orcd-raw-assets/fingerprinting/acrcloud/{filename}.{extension}`
3. `ACRCloudClient.upload_fingerprint(bucket_id, asset_id, raw_bytes)` — internally calls `acrcloud.acrcloud_extr_tool.create_fingerprint_by_filebuffer` to generate a binary fingerprint, then POSTs it to `buckets/{bucket_id}/dedup-files`
4. `ows_sound_recordings.post_acrid(asset_id, acr_id)` writes the returned `acr_id` to OWS via `POST /acrids`
5. Returns `{track_ids: [...]}` — the Track IDs that were updated in OWS

**Key design notes:**
- `ACR_CLOUD_BUCKET_ID` and `ACR_CLOUD_ACCESS_TOKEN` are required at startup; the token is a JWT pulled from `LambdaSecretsManager`.
- HTTP 500/502/504/429 from ACRCloud and `ConnectionError` raise `exceptions.RetryableException` (from `src/common/exceptions`), which signals the caller to retry.
- Files larger than `s3_assets.MAX_FILESIZE_BYTES` raise `s3_assets.FileTooLarge` and are not retried.
- The `ACRCloudClient` is re-instantiated on every invocation (not shared across calls), which is intentional — the token is resolved at module load time.
- Fingerprint generation is traced via `@tracer.wrap` (Datadog ddtrace).

## Required Environment Variables

| Variable | Source | Notes |
|---|---|---|
| `ACR_CLOUD_ACCESS_TOKEN` | `LambdaSecretsManager` / `.env` | JWT for ACRCloud Console API |
| `ACR_CLOUD_BUCKET_ID` | env var | ACRCloud bucket to register fingerprints in |
| `ENVIRONMENT` | env var | `dev` / `qa` / `prod`; defaults to `dev` |
| `SENTRY_DSN` | `LambdaSecretsManager` / `.env` | Optional; Sentry not initialized if absent/empty |
