Contexto: puente limpio surtido ←> yt-extract

CONTRATO DE INTEGRACION (dos modulos puente, uno por lado):
 
  surtido = fuente de verdad de QUIEN se monitorea (channels.json, 38 canales)
            + indice de credibilidad (indice-credibilidad.json, MBFC).
  yt-extract = observatorio VIVO de trainability (Worker/D1: opt-in de entrenamiento
               IA de terceros) + analitica (supervivencia en trending).
 
  LLAVE DE UNION: channel_id (UC...).
 
  FLUJO:
    channels.json --(yt/surtido.py)--> observatory.py --(scan)--> Worker/D1
    Worker/D1 (/deck) --(surtido/trainability.py)--> reporte/trainability.json
 
  MODULO yt-extract/yt/surtido.py:
    surtido_dir()  -> resuelve dir de surtido sin hardcodear:
                      env SURTIDO_DIR -> ../surtido -> ~/surtido -> default
    load_channels() / load_cred_index()
 
  MODULO surtido/trainability.py:
    construir() -> {fecha, origen, total_canales, opt_in_total, canales:[
      channel_id, nombre, categoria, tipo_medio, sesgo, credibilidad_10,
      opt_all, opt_out, opt_list, n_videos, stale, newest]}
    Fuente: Worker /deck (vivo, CORS) -> fallback snapshot ../yt-extract/data/observatorio.json
    Uso: python trainability.py [--out reporte/trainability.json]
 
  SNAPSHOT cruzado (ya existia): observatory.py save_surtido_snapshot()
    -> escribe surtido/reporte/observatorio.json (resumen para /analisis).
 
  HECHO VERIFICADO: trainability.py -> worker, 38 canales, opt-in 0,
    Cronopedia stale (canal muerto, 0 videos). Merge con sesgo/credibilidad OK.