# Design: Fix Musical Coherence

## Architecture Decisions

### AD1: Bass pattern — constant over composition
The 808 bass pattern is a static 8-bar loop transposed by key. No section-specific variation needed since energy and velocity_mult handle intensity changes.

### AD2: Lead range constraint — filter in _resolve_chord_tones
Rather than post-filter melody output, constrain chord_tones at the source. Remove oct_shift -12/+12 from _resolve_chord_tones(), keeping only oct_shift=0. This limits all chord tones to one octave around tonic (octave 4), producing melodies within ~12 semitones.

### AD3: Chord 7ths — change progression quality strings
CHORD_TYPES already has m7=[0,3,7,10] and 7=[0,4,7,10]. Switch EMOTION_PROGRESSIONS from "min"/"maj" to "m7"/"7". Voice leading code handles any voicing size transparently.

### AD4: Pad movement — arpeggiate in build_pad_track
Replace 3 sustained notes with ascending arpeggio: for each beat, play one chord note, cycling through chord tones. 0.5 beat duration (eighth note), 0.55 volume. Different octave (3) from chords (4).

### AD5: Ozone path — verify and harden
The `_build_plugin()` lookup in `_build_master_fxchain()` already resolves correctly from PLUGIN_REGISTRY. Fix by verifying the path and adding an assertion/guard so empty path never reaches the VST element.

## Implementation Notes

### File changes
1. `scripts/compose.py`:
   - Replace BASS_PATTERN_8BARS with 4-note sparse pattern
   - Replace build_pad_track() with arpeggiated version

2. `src/composer/melody_engine.py`:
   - `_resolve_chord_tones()`: remove oct_shift in (-12, 12), keep only 0

3. `src/composer/chords.py`:
   - EMOTION_PROGRESSIONS: "min"→"m7", "maj"→"7"

4. `src/reaper_builder/__init__.py`:
   - `_build_master_fxchain()`: use PLUGIN_REGISTRY to populate PluginDef path

### Test updates
- test_compose.py: verify bass note positions
- test_melody_engine.py: verify range constraint
- test_chords.py: verify 4-note voicings
- test_calibrator.py: verify Ozone master chain
