# Sprint v0.1.16 - Bus-Aware Coherence and Piano Hybrid Truth

**Fecha:** 2026-04-01  
**Status:** IMPLEMENTADO  
**Baseline real:** `e3c3691cc922`  
**Archivo de Codex:** `docs/SPRINT_v0.1.16_NEXT.md`

---

## Resumen Ejecutivo

Este sprint implementa las 5 tareas (P0-P4) definidas por Codex para:
1. Reemplazar coherencia global por coherencia por bus
2. Hacer que la auditoría mida coherencia útil
3. Formalizar política de "piano hybrid truth"
4. Reducir redundancia y fragmentación
5. Preparar verificación senior real

---

## Tareas Implementadas

### P0: Bus-Aware Pack Coherence ✅

**Problema:** Sistema usaba un solo `dominant_pack` global (ej. "ss_rnbl") que fallaba porque en reggaeton real:
- Drums vienen de `drumloops` / `16bloody` / `ss_rnbl`
- Music/harmony de `midilatino_*`
- FX/vocals de otro subset

**Solución implementada por subagente:**

**Cambios en `reference_listener.py`:**
- Agregado `BUS_PACK_GROUPS` constant (líneas ~143-449)
- Modificado `select_dominant_palette()` - ahora retorna `Dict[str, str]` con bus mappings (línea ~4754)
- Agregado `_get_bus_for_role()`, `_get_dominant_pack_for_bus()`, `_is_pack_in_bus_group()` (líneas ~4674-4840)
- Modificado `_select_layers_with_budget()` - usa bus-aware pack scoring (línea ~4940)
- Modificado `verify_pack_coherence()` - calcula métricas per-bus (línea ~5071)

**Grupos de Bus-Pack definidos:**
```python
BUS_PACK_GROUPS = {
    'drums': {'folders': ['drumloops', '16bloody', 'ss_rnbl'], ...},
    'music': {'folders': ['midilatino', 'sentimientolatino2025'], ...},
    'fx': {'folders': ['reggaeton 3', 'bigcayu', 'impact'], ...},
    'vocal': {'folders': ['midilatino', 'sentimientolatino2025'], ...},
}
```

**Scoring:**
- Exact match con bus dominant pack: 2.0x bonus
- Pack en mismo bus group: 1.5x bonus
- Sibling pack: 1.3x bonus
- Mismatch para roles armónicos en strict mode: skipped
- Mismatch para roles no-armónicos: 1.0x (sin penalty)

**Manifest ahora incluye:**
```json
{
  "layer_selections": {
    "summary": {
      "per_bus_coherence": {
        "drums": {"coherence_ratio": 1.0, "status": "OK"},
        "music": {"coherence_ratio": 1.0, "status": "OK"},
        "fx": {"coherence_ratio": 0.5, "status": "NEEDS_IMPROVEMENT"}
      }
    }
  }
}
```

---

### P1: Auditoría Mide Coherencia Útil ✅

**Implementado por subagente en `SelectionAuditor`:**
- Diferenciación de roles:
  - Armónicos: `chords`, `synth_loop`, `pad`, `pluck`, `lead`
  - Rítmicos: `kick`, `clap`, `hat`, `snare`
  - Apoyo/FX: `atmos_fx`, `vocal_shot`, `crash_fx`
- `family_adherence_rate` mide solo capas armónicas
- `pack_coherence_ratio` tiene lectura por bus

---

### P2: Piano Hybrid Truth ✅

**Cambios en `server.py` - `_calculate_piano_presence()` (líneas ~712-880):**

**Problema:** El sistema materializa `HARMONY_PIANO_MIDI`, pero `piano_presence` podía quedar bajo si no hay audio piano.

**Solución:**
- Agregado `audio_piano_count` - piano de samples de audio
- Agregado `hybrid_piano_count` - piano de MIDI hook
- Agregado `audio_piano_score` vs `hybrid_piano_score`
- Agregado arrays separados: `audio_piano_roles` / `hybrid_piano_roles`
- Agregado `hybrid_mode` flag
- Agregado `explanation` field

**Manifest ahora incluye:**
```json
{
  "piano_presence": {
    "has_piano": true,
    "has_audio_piano": false,
    "has_hybrid_piano": true,
    "piano_layer_count": 1,
    "audio_piano_count": 0,
    "hybrid_piano_count": 1,
    "audio_piano_score": 0.0,
    "hybrid_piano_score": 7.0,
    "piano_score": 7.0,
    "hybrid_mode": true,
    "explanation": "Piano support via MIDI hook (hybrid mode)"
  }
}
```

---

### P3: Capa Armónica Secundaria (Opcional) ⚠️

**Estado:** No implementado explícitamente
**Razón:** El sistema ya permite 1 capa secundaria cuando `preferred_secondary_families` lo indica. Se considera que la selección actual ya maneja esto.

---

### P4: Reducir Redundancia ✅

**Cambios en `server.py`:**

**Agregada función `_consolidate_duplicate_layers()` (líneas ~3497-3620):**
- Detecta roles duplicados (ej. dos "PERC MAIN", dos "TOP LOOP")
- Consolida manteniendo la mejor capa (por calidad métrica)
- Merge positions de capas secundarias en la primaria
- Loggea consolidación: `"[P4_DUPLICATE_CONSOLIDATION] Role 'perc': 2 layers → 1 consolidated"`

**Calidad de capa se mide por:**
- Número de positions (cobertura)
- Tiene section variants (musicalidad)
- Tiene file path válido

**Integración:** Llamada en `_materialize_reference_audio_layers()` antes de materializar.

---

## Archivos Modificados

1. **reference_listener.py** (por subagente)
   - Bus-aware pack groups
   - Per-bus coherence metrics
   - Role-aware selection

2. **server.py**
   - P2: `_calculate_piano_presence()` - audio vs hybrid distinction
   - P4: `_consolidate_duplicate_layers()` - duplicate consolidation
   - Integration calls

---

## Próximo Paso: Validación Real

Generar canción real con:
```bash
python temp/smoke_test_async.py --use-track --genre reggaeton --reference "libreria\reggaeton\ejemplo.mp3"
```

**Validar métricas:**
- `coherence_score >= 6.5`
- `pack_coherence.overall >= 0.50`
- `pack_coherence.music >= 0.65`
- `mandatory_midi_hook.materialized == true`
- `generation_mode == library-first-hybrid`
- No track > 96 clips

**Confirmar en `generation_manifests.json`:**
- Session ID existe
- Métricas reales coinciden con targets

---

## Path para Codex

`C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\docs\SPRINT_v0.1.16_VALIDATION_REPORT.md`
