--- id: "0176" title: "EDA render: models/series/caveats en markdown+PDF + PDF para profile_database" status: pendiente type: feature domain: - registry-quality scope: registry-only priority: media depends: [] blocks: [] related: ["0173", "0174", "0175", "0177"] created: 2026-06-29 updated: 2026-06-29 tags: [eda, datascience, render_eda_markdown, render_eda_pdf, profile_database, pdf, benchmark] --- # 0176 — EDA render: models/series/caveats en markdown+PDF + PDF para profile_database ## Contexto El benchmark `/eda` (29/06/2026, `temp/eda_benchmark/EVALUATION.md`) confirmó que la información de modelos (PCA/KMeans) está completa en el JSON pero **no llega legible a ningún formato**, y que el análisis relacional no tiene salida móvil (PDF). El tercio final del PDF queda ilegible. Hallazgos cubiertos: | Hallazgo | Severidad | Evidencia del benchmark | |---|---|---| | H4 — `models` omitido en Markdown; `models`/`series`/`caveats` como dict crudo truncado en PDF | alto | wine-red `.md` (12 numéricas, PCA valioso) → cero menciones de models. PDF aapl: `- pca: {'n_components': 2, …` cortado a media línea | | H9 — `profile_database` no genera PDF | medio | chinook y sakila con `pdf=null`; análisis relacional solo en Markdown | ### Causa raíz (verificada en código, READ-ONLY) - `python/functions/datascience/render_eda_markdown.py`: tiene formatters para `series` (`:337`) y `caveats` (`:407`), pero **no para `models`** → el bloque PCA/KMeans nunca se renderiza en MD. - `python/functions/datascience/render_eda_pdf.py:50-55`: `_KNOWN_TOP_KEYS` **no incluye** `models`, `series` ni `caveats`, así que caen en `_generic_pages` (`:479-495`) → `_wrap_value` → `str(dict)` truncado a 60-64 chars. Por eso esas tres secciones salen como dict crudo en el PDF. - `python/functions/pipelines/profile_database.py:205-218`: solo escribe MD+JSON, nunca invoca `render_eda_pdf`; no tiene param `emit_pdf`. ## Tareas 1. **H4 — markdown:** añadir una sección `## Modelos` (PCA/KMeans/outliers/normalidad) a `render_eda_markdown.py`, formateando `models.pca` (varianza explicada, top loadings, acumulada), `models.kmeans` (best_k, silhouette, tamaños de cluster) y `models.outliers` como tablas legibles. 2. **H4 — PDF:** en `render_eda_pdf.py`, añadir builders dedicados para `models`, `series` y `caveats` (tablas/listas, no `str(dict)`) y registrarlos en `_KNOWN_TOP_KEYS` + en la lista `builders` (`:595-604`) para sacarlos del volcado genérico. Mantener el contrato dict-no-throw (una sección que falle no aborta el PDF). 3. **Unificar renderers:** asegurar que MD y PDF cubren el mismo conjunto de secciones (`models`, `series`, `caveats`) para que no diverjan otra vez. 4. **H9 — PDF relational:** añadir un renderer PDF DB-level (puede ser una variante en `render_eda_pdf.py` o una función nueva) con: portada de la base, resumen de tablas, join graph filtrado (tras 0175), y FK candidatas. Añadir param `emit_pdf` a `profile_database.py` que lo invoque y devuelva `pdf_path`. 5. Tests: `render_eda_markdown_test.py` (perfil con `models` → aparece sección Modelos); `render_eda_pdf_test.py` (perfil con `models`/`series`/`caveats` → NO aparecen como `str(dict)`; `n_pages` incrementa); test de `profile_database(emit_pdf=True)` → `pdf_path` no nulo, PDF válido. ## Definition of Done | Escenario | Tipo | Comando / evidencia | Resultado esperado | |---|---|---|---| | Golden: models en MD | e2e | re-correr `profile_table(run_models=True)` sobre wine-red y leer el `.md` | sección `## Modelos` con PCA (varianza explicada) y KMeans (silhouette) legibles | | Golden: PDF legible | e2e | re-correr sobre aapl y `pdftotext` del PDF | `models`/`series`/`caveats` como tablas, sin `{'n_components': 2, …` truncado | | Edge: perfil sin models | unit | `render_eda_markdown_test.py`/`render_eda_pdf_test.py` con `models=None` | sección omitida limpiamente, sin crash | | Edge: PDF relational | e2e | `profile_database(emit_pdf=True)` sobre chinook | `pdf_path` no nulo; PDF con resumen de tablas + join graph | | Error: sección corrupta | unit | `render_eda_pdf` con una sección con tipo inesperado | esa sección se omite con nota; PDF sigue válido (≥1 página) | | Mecánica | — | `./fn run render_eda_markdown_py_datascience`, `./fn run render_eda_pdf_py_datascience`; `fn index` | tests verdes; índice limpio | Re-correr el benchmark sobre un single-table con modelos (wine-red) y sobre un relational (chinook) y confirmar que models llega al MD y al PDF, y que `profile_database` emite PDF. ## Notas Issue derivado de `temp/eda_benchmark/EDA_ISSUES.md`. Tipo `feature` porque, además de arreglar el volcado crudo (H4, fix), añade un renderer PDF relational nuevo (H9). La información ya existe en el JSON; este issue solo la hace legible en las dos salidas pensadas para humanos. Hermanos: 0173, 0174, 0175, 0177.