# SPRINT 4 — BLOQUE A: CARGA REAL, DIAGNÓSTICO Y ESTABILIZACIÓN (T001-T050) > **Fecha**: 2026-04-11 > **Estado Sprint 3**: ✅ COMPLETO — 119 tools MCP, 64 handlers, 3 engines nuevos > **Objetivo Sprint 4-A**: Que TODO lo que "dice" que hace, LO HAGA REALMENTE en Ableton > **Revisión**: Qwen --- ## CONTEXTO Sprint 3 entregó código que compila 100%. El problema: muchas acciones retornan `"loaded": True` sin verificar que Ableton realmente las ejecutó. Este bloque se enfoca en tres pilares: 1. **Verificación real** — cada handler confirma el estado POST-ejecución en Live 2. **Integración completa** — browser API ya implementada, ahora se usa en TODO el sistema 3. **Diagnóstico** — herramientas para que el usuario sepa exactamente qué funciona --- ## FASE A1: VERIFICACIÓN POST-EJECUCIÓN (T001-T010) **T001** — `_cmd_load_sample_to_clip`: Agregar `_verify_clip_has_audio(slot)` que inspecciona `slot.has_clip` y `clip.length > 0` DESPUÉS de la carga. Retorna `verified: true/false` con `duration_beats` real si el clip existe. **T002** — `_cmd_insert_device`: Agregar `_verify_device_on_track(track, device_name)` que compara lista de devices ANTES y DESPUÉS. Retorna `verified: true` + `device_index` real si el device apareció en `track.devices`. **T003** — `_cmd_create_arrangement_midi_clip`: Verificar si `arrangement_clips` API funcionó chequeando el clip existe en el track. Si Session fallback, marcar `view: "session_fallback"` y retornar `clip_index` + URL del slot real. **T004** — `_cmd_load_sample_to_drum_rack_pad`: Verificar que el pad tiene cadena después del intento. Acceder a `pad.chains[0].devices[0].sample.file_path` y comparar con el fname buscado. Retornar `verified_path`. **T005** — `_cmd_generate_dembow_clip`: Verificar que las notas se escribieron exactamente. Leer el clip con `clip.get_notes()` y comparar count. Retornar `notes_written: N, notes_verified: M`. **T006** — `_cmd_generate_midi_clip`: Agregar verificación de notas post-escritura. Si `clip.get_notes()` retorna vacío cuando se enviaron notas, loguear el error y reintentar con `replace_selected_notes` si disponible. **T007** — `_cmd_create_drum_kit`: Después de crear el Drum Rack, verificar que `track.devices` contiene el device. Acceder a `device.drum_pads` y contar pads activos. Retornar `pads_active`, `drum_rack_index`. **T008** — `_cmd_configure_eq`: Verificar que el EQ Eight está en la cadena. Leer `device.parameters` y confirmar que se aplicaron los valores. Retornar `parameters_verified: {band: value}`. **T009** — `_cmd_setup_sidechain`: Verificar que el Compressor tiene `sidechain_active`. Acceder a `device.sidechain` si existe. Retornar `sidechain_confirmed: true/false`. **T010** — Crear handler `_cmd_verify_track_setup(track_index)`: - Lista todos los devices del track - Lista clips activos en Session View - Informa volumen, pan actual - Retorna snapshot completo del track para debugging --- ## FASE A2: BROWSER API — USAR EN TODO EL SISTEMA (T011-T020) **T011** — `_cmd_load_samples_for_genre` (T008): Actualmente usa solo `sample_selector.select_for_genre()` para paths. Integrar `_browser_load_audio()` para cada sample, con fallback a `create_audio_clip`. Retornar qué método funcionó por cada sample. **T012** — `_cmd_create_drum_kit` (T009): Actualmente crea Drum Rack via `create_midi_track()` pero no carga el Drum Rack device. Integrar `_browser_load_device(t, "Drum Rack", "instruments")` antes de cargar samples. Verificar que el Drum Rack apareció antes de intentar cargar pads. **T013** — `_cmd_build_track_from_samples` (T010): Usar `_browser_load_audio()` en lugar de confiar en `create_audio_clip`. Agregar lógica de fallback: si browser falla, crear MIDI track con nota de instrucción. **T014** — `_cmd_insert_device` → extender lookup: Actualmente busca solo en una sección. Agregar búsqueda secundaria en TODAS las secciones si la primera falla. Orden: `instruments → audio_effects → midi_effects → packs`. **T015** — Nuevo handler `_cmd_scan_browser_section(section_name, depth=2)`: - Escanea una sección del browser Live y retorna árbol de items - Sections: "instruments", "audio_effects", "sounds", "user_folders", "packs" - Útil para debug: saber exactamente qué ve el sistema en el browser - Retorna lista de items con `name`, `is_loadable`, `is_folder` **T016** — Nuevo tool MCP `scan_browser_section(section, depth)` en `server.py`: - Llama a `_cmd_scan_browser_section` - Permite al usuario descubrir qué devices/samples tiene disponibles - Retorna JSON con árbol navegable **T017** — `_cmd_configure_eq`: Si el device no existe en el track, PRIMERO insertar EQ Eight via `_browser_load_device`, LUEGO configurar parámetros. Secuencia: insert → verify → configure. **T018** — `_cmd_configure_compressor`: Si no hay Compressor, insertar via browser antes de configurar. Verificar la inserción. Mismo patrón que T017. **T019** — `_cmd_setup_sidechain`: Insertar Compressor si no existe, configurar la fuente de sidechain. Usar `device.sidechain_enabled = True` si disponible. Retornar los parámetros realmente configurados. **T020** — Nuevo handler `_cmd_add_libreria_to_browser()`: - Lee path de `libreria/reggaeton` desde constante - Intenta agregar el folder a Live's user library via `application().browser` - Retorna `added: true/false` con instrucción manual si falla --- ## FASE A3: ARRANGEMENT VIEW — IMPLEMENTACIÓN COMPLETA (T021-T030) **T021** — `_cmd_create_arrangement_midi_clip`: Agregar soporte para `song.record_mode`. Si `song.record_mode` está disponible, configurar overdub antes de fire. Retornar `arrangement_mode_set: true/false`. **T022** — Nuevo handler `_cmd_set_arrangement_position(bar)`: - `song.current_song_time = bar * beats_per_bar` - `app.view.show_view("Arranger")` - Retorna posición actual del playhead **T023** — Nuevo handler `_cmd_fire_clip_to_arrangement(track_index, clip_index, target_bar)`: - Pos playhead en `target_bar` - Activa `song.arrangement_overdub = True` - Dispara el clip: `track.clip_slots[clip_index].fire()` - Espera `clip.length` beats en la queue de `_pending_tasks` - Desactiva overdub: `song.arrangement_overdub = False` - Retorna `recorded_to_bar: target_bar` **T024** — `_cmd_duplicate_session_to_arrangement` (T014): Reescribir usando `_cmd_fire_clip_to_arrangement` para cada clip+escena. Calcular posición en bars basada en `scene_index * section_length`. Retorna clips colocados + posición. **T025** — Nuevo handler `_cmd_get_arrangement_clips(track_index)`: - Lee todos los clips de arrangement via `track.arrangement_clips` si disponible - Retorna lista con `name`, `start_time`, `length`, `has_notes` - Si no disponible, retorna vacío con `method: "not_available"` **T026** — Nuevo handler `_cmd_show_arrangement_view()`: - `app.view.show_view("Arranger")` - `app.view.show_view("Detail/Clip")` para mostrar detalle - Retorna `view: "arranger"` **T027** — Nuevo handler `_cmd_show_session_view()`: - `app.view.show_view("Session")` - Retorna `view: "session"` **T028** — `_cmd_build_arrangement_structure`: Usa `_cmd_fire_clip_to_arrangement` para colocar clips reales en posiciones de la estructura (Intro, Verse, Drop, etc.) en lugar de solo crear escenas en session view. **T029** — Nuevo handler `_cmd_loop_arrangement_region(start_bar, end_bar)`: - `song.loop_start = start_bar * beats_per_bar` - `song.loop_length = (end_bar - start_bar) * beats_per_bar` - `song.loop_on = True` - Retorna `loop_set: true` **T030** — Nuevo handler `_cmd_capture_to_arrangement()`: - Equivalente a "Capture" de Live: `app.get_document().capture_midi()` si disponible - Fallback: instrucción de cómo usar Capture manualmente - Retorna `captured: true/false` --- ## FASE A4: DIAGNÓSTICO Y MONITOREO (T031-T040) **T031** — Nuevo handler `_cmd_get_live_version()`: - `Live.Application.get_application().get_major_version()` - `Live.Application.get_application().get_minor_version()` - Retorna `version: "12.x.x"`, `build: N` **T032** — Nuevo handler `_cmd_get_track_details(track_index)`: - Snapshot completo de un track: devices, clips, volumes, routing - Para debugging: `has_input`, `has_output`, `arm`, `mute`, `solo` - Lista cada device con parámetros accesibles **T033** — Nuevo handler `_cmd_get_device_parameters(track_index, device_index)`: - Lista todos los parámetros de un device - `device.parameters` → `{name, value, min, max, is_quantized}` - Útil para saber cómo configurar el device vía API **T034** — Nuevo handler `_cmd_set_device_parameter(track_index, device_index, param_name, value)`: - Busca parámetro por nombre en `device.parameters` - Setea `param.value = value` - Verifica que el cambio se aplicó - Retorna `parameter`, `old_value`, `new_value` **T035** — Nuevo handler `_cmd_get_clip_notes(track_index, clip_index)`: - Lee las notas de un MIDI clip via `clip.get_notes()` - Retorna lista de `{pitch, start, duration, velocity, mute}` - Con estadísticas: `note_count`, `min_pitch`, `max_pitch`, `duration_bars` **T036** — Nuevo handler `_cmd_test_browser_connection()`: - Verifica que `application().browser` es accesible - Lista las secciones disponibles: sounds, instruments, audio_effects, etc. - Retorna `browser_ok: true/false`, `sections: [...]` **T037** — Nuevo handler `_cmd_test_sample_loading(sample_path)`: - Tests: `os.path.isfile()` → path OK - Tests: `_browser_load_audio()` → browser OK - Tests: `create_audio_clip()` si disponible - Retorna `path_ok`, `browser_ok`, `direct_ok`, `recommended_method` **T038** — Nuevo handler `_cmd_get_session_state()`: - `song.current_song_time` → posición actual - `song.is_playing`, `song.tempo`, `song.signature_numerator` - Lista clips activos por track - Retorna snapshot completo del estado de Session **T039** — Nuevo tool MCP `get_system_diagnostics()` en `server.py`: - Combina: get_live_version + test_browser_connection + get_session_state - Retorna JSON con estado completo del sistema - Primer tool que ejecutar para diagnosticar problemas **T040** — Nuevo tool MCP `test_real_loading(sample_path)` en `server.py`: - Llama a `_cmd_test_sample_loading` - Retorna qué métodos de carga funcionan en el Live actual - Guía al usuario sobre qué esperar --- ## FASE A5: ROBUSTEZ Y ESTABILIDAD (T041-T050) **T041** — Agregar timeout global a `_cmd_*` handlers: Si un handler tarda más de 3s (detectado via `time.time()`), retornar `timeout: true` y limpiar `_pending_tasks` parcialmente. Previene bloqueos de Ableton. **T042** — `_dispatch()`: Agregar manejo de `JSONDecodeError` y `KeyError` explícitos. Retornar error descriptivo con el comando que falló. Loguear en Ableton con `self.log_message`. **T043** — Proteger `update_display()`: Atrapar excepciones dentro del loop de `_pending_tasks`. Si una task lanza excepción, remover y continuar con la siguiente. Nunca dejar que una task rota bloquee el drain. **T044** — `_tcp_server_thread`: Si la conexión se cierra abruptamente, cerrar el socket limpiamente. Agregar `socket.SO_REUSEADDR` si no está presente. Reiniciar listener automáticamente tras error de conexión. **T045** — Agregar límite a `_pending_tasks`: Si la queue supera 100 items, droppear las tareas más viejas y loguear warning. Previene acumulación sin límite cuando Ableton está bajo carga y `update_display()` no puede drenar rápido. **T046** — `_cmd_get_tracks()`: Si un track da error al leer un atributo (e.g., track sin nombre), continuar con el siguiente en lugar de fallar todo. Agregar `try/except` granular por atributo. **T047** — `_cmd_generate_full_song()`: Si un sub-handler falla durante el pipeline, continuar con los siguientes tracks. Retornar lista de errores al final pero no abortar. Comportamiento "best effort" para producción completa. **T048** — Todos los handlers que crean tracks: Verificar que el índice solicitado no excede `len(song.tracks)`. Si se intenta acceder a track[N] y N>=len, retornar error claro en lugar de IndexError sin contexto. **T049** — `_browser_search`: Agregar límite de tiempo: si la recursión supera 5 segundos (verificar con `time.time()`), abortar y retornar `None` en lugar de bloquear el thread de Ableton indefinidamente. **T050** — Crear `_cmd_health_check()`: - Ejecuta 5 checks: TCP OK, song accesible, tracks accesibles, browser accesible, update_display activo - Retorna score 0-5 y descripción de cada check - Tool MCP `health_check()` que llama a este handler - Primero que ejecutar tras abrir Ableton --- ## ARCHIVOS A MODIFICAR (Bloque A) | Archivo | Cambios | |---------|---------| | `__init__.py` | +25 handlers nuevos, robustez en handlers existentes | | `mcp_server/server.py` | +10 tools MCP: scan_browser, health_check, get_system_diagnostics, test_real_loading, etc. | ## RESTRICCIONES 1. Compilar tras cada archivo: `python -m py_compile ""` 2. `libreria/` → solo lectura 3. NO modificar engines del Sprint 1/2/3 4. Handlers de verificación son SOLO-LECTURA: no mutan estado 5. Retornar siempre JSON con `status` + `result` o `error`