# CLAUDE.md

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

## Purpose

`sr-record-event` records persistent events that occur during sound recording delivery (e.g., start, success, failure, undelivered) to create a historical log. It is invoked as a step within a Step Functions delivery state machine and publishes a structured message to the Kafka topic `event.orchardSoundRecording.delivery`.

## Development Commands

All commands run from this directory (`lambda/sr-record-event/`):

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

# With exit codes (CI-style)
docker compose up --exit-code-from lint-and-test --abort-on-container-exit --build lint-and-test

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

# Run a specific test
TEST_ARGS="-k test_format_kafka_message_failure" docker compose up --build lint-and-test

# Run with HTML coverage report (output in htmlcov/)
COV_REPORT=html docker compose up --build lint-and-test

# Start the function locally (port 9000)
docker compose up --build -d function

# Invoke locally
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d @tests/dev_sample_event.json
```

## Architecture

The handler (`src/app.py`) does one thing: receive a Step Functions event, reshape it into a Kafka message via `_format_kafka_message`, and publish it using `src/common/connectors/kafka_producer`.

**Event → Kafka message mapping:**
- `sound_recording.id` / `sound_recording.version` are passed through directly.
- `execution_name` maps to `step_function_execution_id`.
- `service` defaults to `'TikTok (Audio Fingerprinting)'` if absent.
- `execution_type` is resolved by `_determine_execution_type`: prefers `delivery_type` (uppercased) over `execution_type`.
- `message.status` is derived from event shape: `'error'` if `error` key present, `'undelivered'` if `details.undelivered` is truthy, otherwise `'ok'`. The `message.details` payload is `event['error']` on error, `event['details']` otherwise.
- `event_type` is overridden to `'undelivered'` when `details.undelivered` is truthy.

**Constants** (`src/constants/delivery_event.py`) define the canonical service name and event type strings used in the mapping logic.

**Required env vars** (`config.py`): `KAFKA_BROKERS`, `KAFKA_TOPIC`. Both raise `KeyError` on startup if missing (they are set to empty strings in the test container via `docker-compose.yaml`).

## Testing

Unit tests live in `tests/unit/` and are the primary test surface:
- `test_index.py` — covers `_format_kafka_message` for all status paths (ok, error, undelivered) and Sentry init behavior.
- `connectors/test_kafka.py` — covers the shared `kafka_producer` connector (delivery report, produce message).

Integration tests in `tests/integration/` require real AWS access and are skipped in CI. The placeholder `test_invoke_lambda` intentionally fails (`assert 1 == 0`) and must be replaced before use.

Test fixtures are in `tests/unit/conftest.py`. The base `mock_delivery_event` fixture represents a minimal start event without `delivery_type`; `mock_delivery_event_with_type` adds `delivery_type: 'FULL_DELIVERY'`.

Multiple sample event files exist in `tests/` for local invocation against QA data (`qa_sample_event_*.json`) and a dev variant (`dev_sample_event.json`).

## Local Dev Notes

- Copy `.env.shadow` to `.env` and fill in `SENTRY_DSN` to enable Sentry locally (optional).
- On Apple Silicon, `confluent-kafka` requires `librdkafka` if installing outside Docker: `brew install librdkafka` and set `C_INCLUDE_PATH` / `LIBRARY_PATH` in `.zshrc` (see README.md for exact paths).
- The `common/` directory is a symlink to `../../common` and provides `kafka_producer`, `logger`, and exception classes used by this Lambda.
