Files
reaper-control/.sdd/changes/archive/2026-05-03-compose-test-sync/design.md
renato97 48bc271afc feat: SDD workflow — test sync, song generation + validation, ReaScript hybrid pipeline
- compose-test-sync: fix 3 failing tests (NOTE_TO_MIDI, DrumLoopAnalyzer mock, section name)
- generate-song: CLI wrapper + RPP validator (6 structural checks) + 4 e2e tests
- reascript-hybrid: ReaScriptGenerator + command protocol + CLI + 16 unit tests
- 110/110 tests passing
- Full SDD cycle (propose→spec→design→tasks→apply→verify) for all 3 changes
2026-05-03 22:00:26 -03:00

3.7 KiB

Design: compose-test-sync

Technical Approach

Fix 3 failing tests by replacing calls to removed/changed compose.py APIs with their current equivalents. Each fix is surgical — only the broken import or call signature changes, no test logic rewrites.

File Changes

File Action Description
tests/test_section_builder.py Modify Replace root_to_midi with NOTE_TO_MIDI dict lookup
tests/test_render_cli.py Modify Remove obsolete DrumLoopAnalyzer patch, retain SampleSelector if still needed
tests/test_compose_integration.py Modify Remove analysis arg, use section name "chorus" instead of "verse"

Fix Details

Fix 1: test_root_to_midi (test_section_builder.py:121)

Problem: Test imports root_to_midi which no longer exists in compose.py. Fix: Replace the import and the two assertions.

# Before
from scripts.compose import root_to_midi
assert root_to_midi("A", 4) == 69
assert root_to_midi("C", 4) == 60

# After
from scripts.compose import NOTE_TO_MIDI
assert NOTE_TO_MIDI["A"] + (4 + 1) * 12 == 69
assert NOTE_TO_MIDI["C"] + (4 + 1) * 12 == 60

NOTE_TO_MIDI is at compose.py:37 and maps {"A": 69, "C": 60, ...}. The formula NOTE_TO_MIDI[root] + (octave + 1) * 12 reconstructs the old root_to_midi behavior.


Fix 2: test_melody_uses_pentatonic (test_compose_integration.py:200)

Problem 1: build_melody_track no longer accepts analysis as 5th arg. Problem 2: build_lead_track (called inside build_melody_track) skips any section not named "chorus", "chorus2", or "final". Test passes "verse" → zero clips generated.

Fix: Remove analysis arg from call, change section name to "chorus".

# Before
sections = [SectionDef(name="verse", bars=4, energy=1.0)]
offsets = [0.0]
track = build_melody_track(sections, offsets, "A", True, seed=42)

# After
sections = [SectionDef(name="chorus", bars=4, energy=1.0)]
offsets = [0.0]
track = build_melody_track(sections, offsets, "A", True, seed=42)

Note: analysis = _fake_analysis() at line 204 becomes unused — leave it in place (no harm) or remove if preferred.


Fix 3: test_main_without_render_produces_rpp (test_render_cli.py:44)

Problem: Test patches scripts.compose.DrumLoopAnalyzer which no longer exists in compose.py. Fix: Remove patch("scripts.compose.DrumLoopAnalyzer") from both the mock setup and the with statement.

# Before
with patch("scripts.compose.SampleSelector") as mock_cls, \
     patch("scripts.compose.DrumLoopAnalyzer") as mock_a_cls:

# After
with patch("scripts.compose.SampleSelector") as mock_cls:

Lines 48-55 (fake DrumLoopAnalysis object) and lines 68-70 (mock analyzer setup) should be removed since fake_analysis and mock_a are no longer used.

Verify SampleSelector patch is still functional — if SampleSelector was also removed, remove that patch too and simplify the mock block.

Verification Strategy

  1. Run pytest tests/ -q — expect 90/90 pass
  2. Run each fixed test individually to confirm:
    • pytest tests/test_section_builder.py::TestHelpers::test_root_to_midi -v
    • pytest tests/test_compose_integration.py::TestComposeIntegration::test_melody_uses_pentatonic -v
    • pytest tests/test_render_cli.py::TestComposeNoRender::test_main_without_render_produces_rpp -v
  3. Confirm no compose.py files modified: git diff --name-only scripts/

Open Questions

  • SampleSelector still used?: Verify SampleSelector is still imported/patched in compose.py before leaving that patch in place. If also removed, strip it.
  • None: All three fixes are clear from the proposal and code inspection.