# Tasks: Transitions FX

## Phase 1: FX Transition Map

- [x] 1.1 Add `FX_TRANSITIONS` dict to `scripts/compose.py`: `{boundary_index: (type, start_offset, length, fade_in, fade_out)}` with 8 entries matching design boundary map
- [x] 1.2 Add `FX_ROLE = "fx"` constant referencing ATONAL_ROLES membership

## Phase 2: Build FX Track

- [x] 2.1 Implement `build_fx_track(sections, offsets, selector, seed=0)` — iterates `FX_TRANSITIONS`, computes clip positions from offsets, selects FX samples
- [x] 2.2 For each boundary: call `selector.select_one(role="fx", seed=seed + idx)` to pick sample
- [x] 2.3 Create `ClipDef(position, length, name, audio_path, fade_in, fade_out)` per boundary
- [x] 2.4 Build `TrackDef("Transition FX", volume=0.72, clips=[...], send_level={reverb: 0.08, delay: 0.05})`
- [x] 2.5 Add docstring explaining boundary map and FX types (riser/impact/sweep/transition)

## Phase 3: Integration

- [x] 3.1 Call `build_fx_track()` in `main()` after clap track, before pad track
- [x] 3.2 Verify send wiring loop handles new track (existing code; confirm no regression)

## Phase 4: Testing & Verification

- [x] 4.1 Write unit test: `build_fx_track` returns TrackDef with exactly 8 clips
- [x] 4.2 Write unit test: clip positions and fade values match design's boundary map
- [x] 4.3 Write unit test: all clips have `audio_path` set (not None)
- [x] 4.4 Write integration test: `compose.py --bpm 99 --key Am --output /tmp/test.rpp` produces valid .rpp with "Transition FX" track
- [x] 4.5 Run full `pytest` suite — all 110 existing tests pass
