Skip to content

feat(front): Resumen de evolución como pantalla principal - #9

Merged
AnderVarela merged 16 commits into
devfrom
feature/front-dashboard-evolucion
Sep 19, 2026
Merged

AnderVarela merged 16 commits into
devfrom
feature/front-dashboard-evolucion

Conversation

@AnderVarela

Copy link
Copy Markdown
Contributor

Qué es

Una pantalla nueva, Resumen, que pasa a ser la principal (/): enseña de un vistazo cómo ha ido evolucionando cada tarea, nivel por nivel. Live pasa a /live. Es la evidencia del criterio «iteración y mejora medida» del eje B.

Qué incluye

Resumen (/)

  • Una sección por tarea y, dentro, una tarjeta por nivel con las cuatro métricas de v_run_summary (tasa de éxito, tiempo de ciclo, margen de estabilidad, error de colocación): dónde está ahora, cuánto ha cambiado desde la primera ejecución y su curva.
  • Lista lateral fija «De un vistazo» con el veredicto de cada nivel (Mejora, Empeora, Mixto, Sin cambios) y «Cómo leerlo».
  • Selector de clase de datos: Medidos, Oracle y Sembrados nunca se mezclan en una serie.
  • Aplica la regla de comparability(): la curva usa solo ejecuciones comparables (en un nivel, las del rango de semillas más usado). Las demás se dejan fuera y se cuentan («+10 con otras semillas»).
  • Iconos de ayuda (InfoTip) en las métricas, en el selector de clases y en «De un vistazo».
  • La flecha de cada cambio dice si va a mejor o peor (color y flecha), y el signo del texto si el valor subió o bajó: un tiempo que sube es ↓ +0.6 s en rojo.

Live

  • El aviso distingue conexión perdida (falla la consulta o el canal de Realtime) de el episodio no envía datos (canal sano, nada recibido en 30 s). Antes cualquier silencio decía «Conexión perdida».
  • La marca de última señal pertenece a su episodio: al pasar al siguiente ya no arrastra el silencio del anterior.

Detalle del episodio y comparativa

  • Selector Esquema | Captura en lugar del enlace «Ver captura», y capturas como tarjeta con la proporción de la foto.
  • Los rellenos del dibujo del palé son opacos: la muestra «último» de la leyenda coincide con el dibujo.
  • Arreglo: la comparativa fallaba («two children with the same key») al comparar dos ejecuciones del mismo commit.

Otros: nueva tarea paletizado-guionizado en el vocabulario, y AGENTS.md con las rutas y el estado nuevos.

⚠️ Conflicto resuelto con dev

dev trajo su propio arreglo del aviso de Live (2d04f2f: descartar episodios running de más de 15 min y subir el umbral a 20 s). Se conservan sus dos cambios de fondo (el descarte de huérfanos y la justificación del umbral) y se mantiene la separación de esta rama entre conexión perdida y sin datos, con un umbral de 30 s. Conviene que quien hizo aquel arreglo mire LiveScreen.helper.ts.

Verificado

  • npm run lint (eslint, colores, contraste), tsc y npm run build pasan tras la fusión con dev.
  • Chrome con datos reales de Supabase: Resumen (claro y oscuro), ayudas, comparativa con dos ejecuciones del mismo commit sin errores en consola, capturas en esquema y captura, sin scroll de página a 1440 y 390 px.

No verificado / a tener en cuenta

  • Los avisos de Live («conexión perdida» y «sin datos») no se han visto en vivo: no había ningún episodio corriendo al probar; solo el estado sin directo.
  • Las ayudas con el teclado (Tab) no se han probado: el navegador automatizado no dispara el foco en una pestaña de fondo.
  • Desborde de 105 px a 800 px de ancho en el detalle de una ejecución, por el selector de episodio de la barra de identidad. Es anterior a esta rama y no se ha tocado.
  • Con datos de una sola ejecución por nivel, las curvas son un punto y el veredicto es «Sin comparación».

Trend (átomo) dibuja la línea de una serie, un punto por ejecución: escala del mínimo al
máximo de la propia serie (enseña la forma de la evolución, no el valor, que ya dice el
número de al lado), la referencia punteada del primer valor, trazo discontinuo para datos
que no son de verdad, y cada punto con su detalle al pasar el ratón.

SegmentedControl (radios nativos), ChangePill (la flecha dice hacia dónde se movió el valor
y el color si eso es bueno o malo) y MetricTrend (valor actual, cambio desde el principio
y línea) son moléculas construidas con ellas. Iconos arrowUp y minus, y tono warn en Badge.

changeTone y shortDate pasan a lib/ui: el tono de un cambio lo comparten la comparativa de
ejecuciones y el resumen, y ya no vive duplicado en ComparePanel.helper.
LevelCard enseña cómo va un nivel de una tarea: cada métrica con su valor actual, cuánto
ha cambiado desde la primera ejecución y su línea, y un veredicto arriba (Mejora, Empeora,
Mixto, Sin cambios) que resume cuántas mejoran y cuántas empeoran. TaskSection agrupa una
tarjeta por nivel: se compara un nivel consigo mismo a lo largo del tiempo, nunca un nivel
con otro (el criterio de éxito es distinto).

Las cuatro métricas salen de v_run_summary: tasa de éxito, tiempo de ciclo, margen de
estabilidad y error de colocación. Una métrica que la tarea no mide (la estabilidad de la
inducción) no aparece, en vez de salir como «—». El cambio es la resta del último valor y el
primero (dos números que ya calculó la vista); el color dice si eso es bueno o malo según la
métrica (un tiempo o un error que bajan mejoran).

Las clases de datos NO se mezclan en una serie: medidos, oracle y sembrados van aparte, con
etiqueta y trazo discontinuo los que no son de verdad, y un aviso si la serie mezcla rangos
de semillas distintos («se compara suerte, no código»).
La curva se limitaba a las ejecuciones comparables con la más reciente. Con datos reales
(pruebas de humo, cada una con semillas distintas) una sola ejecución suelta se quedaba con la
serie y dejaba fuera a todas las demás: la tarjeta salía con una ejecución y «sin comparación».

Ahora la referencia es el rango de semillas con MÁS ejecuciones (a igualdad, el de la más
reciente), que es el protocolo real de un benchmark. Sigue usando comparability(), la misma
regla que bloquea la comparativa: lo que no la cumple no entra en la curva, y la tarjeta dice
cuántas se dejan fuera («+3 con otras semillas»).
/ pasa a ser el Resumen y Live se mueve a /live. La barra tiene tres pestañas (Resumen, Live,
Ejecuciones); routes.ts reúne las rutas y activeTab distingue las tres.

El resumen enseña cómo ha evolucionado cada tarea, nivel por nivel, con las métricas de
v_run_summary (tasa de éxito, tiempo de ciclo, margen de estabilidad y error de colocación).
Para leerlo de un vistazo:

- «De un vistazo»: un chip por tarea y nivel con su veredicto (Mejora, Mixto, Empeora, Sin
  comparación); pulsarlo lleva a su tarjeta. VerdictChip llama a scrollIntoView y no usa el
  #hash: la que scrollea es un contenedor de la pantalla, no el documento.
- Cada tarjeta: valor actual, cambio desde la primera ejecución (la flecha dice hacia dónde
  se movió el valor y el color si eso es bueno o malo) y la línea de evolución.
- Un selector de clase de datos: medidos, oracle y sembrados NO se mezclan nunca en una
  serie; por defecto lo medido y, si no hay, lo primero que haya, con su aviso.
- Una leyenda de lectura, en una línea.

No hace falta ningún endpoint nuevo. Reutiliza useRuns con la misma clave que Ejecuciones.
La pantalla tiene altura fija y scrollea por dentro (la página no scrollea nunca); sus hijos
no se encogen, porque las tarjetas llevan overflow: hidden y en una columna flex se
aplastarían. Con tres pestañas la barra desbordaba 27 px a 390 px: se aprietan en móvil.

AGENTS.md: rutas y estado al día.
Con pocos niveles la tarjeta ocupaba la mitad de la pantalla y el resto quedaba en blanco, y «De
un vistazo» era un bloque enorme con un solo chip.

- Dos columnas que reparten todo el ancho: a la izquierda, una tarjeta por nivel a todo el ancho;
  a la derecha, fija al bajar, «De un vistazo» (una lista vertical de niveles con su veredicto y
  cuántas métricas mejoran o empeoran) y «Cómo leerlo». En pantalla mediana pasa arriba, con la
  lista y la guía lado a lado; en móvil, apiladas.
- Las métricas de una tarjeta son mosaicos que se reparten el ancho de LA TARJETA (container
  query): 1 columna estrecha, 2×2 mediana y todas en fila si es muy ancha. Antes se repartían 3+1
  y quedaba un mosaico huérfano.
- Cada mosaico apila valor, cambio y línea, y el gráfico es más ancho (viewBox 400×64) para que no
  se vea letterboxed en un mosaico grande.
- VerdictChip pasa a VerdictRow y OverviewStrip a OverviewPanel: ya no son ni chip ni franja.

Comprobado en Chrome con datos reales y con un mock de varias tareas y niveles, en los dos temas,
y con iframes de 1850, 1440, 1100, 1000, 800, 390 y 360 px: la página no scrollea ni desborda en
ninguno y la lista lateral se queda fija al bajar.
…ard-evolucion

Trae de dev el alzado a escala del palé con la captura real junto al esquema (PR #6) y la tarea
nueva paletizado-guionizado (vocabulario: schema.py, el CHECK de SQL y TASK_TEXT).

Un conflicto, en components/molecules/index.ts: los dos lados solo añadían exportaciones
(las del resumen y SnapshotView); se conservan todas.

El resumen agrupa por tarea y ordena las que no conoce detrás de paletizado e inducción, así
que la tarea nueva sale como sección propia sin tocar nada. Comprobado con npm run lint, tsc y
next build sobre el árbol fusionado.
Las tarjetas se veían apretadas. Se abren los huecos del resumen: 32 px entre las tarjetas de
nivel (antes 20), 52 entre tareas (36), 28 entre la lista «De un vistazo» y la guía de lectura
(20), 40 entre la columna principal y la lateral (28) y 36 entre bloques de la pantalla (28).
Dentro de una tarjeta de nivel, 20 px entre mosaicos y 28 de relleno lateral (16 y 24).

En pantalla estrecha los huecos se reducen (32 entre columnas, 36 entre tareas).

Comprobado en el servidor de desarrollo con un mock de varias tareas y niveles y con iframes de
1850, 1440, 1000, 800, 390 y 360 px: la página no scrollea ni desborda en ninguno.
…vía datos

Antes 8 s sin eventos se leían como «Conexión perdida», aunque el canal de Realtime
estuviera sano y solo callara quien produce (un paso lento, o un episodio que se
quedó en running porque el proceso se cayó). Ahora:

- conexión perdida: falla la consulta o el canal avisa de CHANNEL_ERROR, TIMED_OUT o CLOSED.
- sin datos: canal sano y nada recibido en 30 s; aviso propio, sin «Reintentar».

La marca de última señal pertenece a su episodio: al pasar al siguiente de una
ejecución ya no arrastra el silencio del anterior.
…coincide con ellos

Con transparencia, el último paquete se veía más oscuro que la muestra de la leyenda en
cuanto había otro debajo (capa 2 sobre capa 1). Ahora se mezclan con --surface: un paquete
tapa al de debajo y su color no depende de lo que haya detrás.
- «Ver captura» / «Ver esquema» (un enlace subrayado) pasa a un control segmentado
  Esquema | Captura en la cabecera, siempre con las dos opciones a la vista. SegmentedControl
  gana la variante compact. La leyenda solo se enseña con el esquema.
- La captura va en un marco que ocupa todo el panel, con las esquinas y el borde del resto
  de la interfaz, sin recortar la foto, y con una etiqueta «captura del simulador».
- La cabecera de un panel pasa a línea siguiente si leyenda y control no caben (390 px).
… sin franjas

Antes iba en un marco del ancho del panel con la foto centrada y franjas vacías a los
lados. Ahora la propia foto tiene esquinas y borde, y se dimensiona con las medidas del
hueco (container query) para ocupar lo máximo posible sin recortar ni deformar.
Además se quita el aro de foco duplicado del control segmentado.
Un cambio a peor salía con la flecha hacia arriba cuando el número subía (un tiempo de
ciclo de +0.6 s), contradiciendo la propia leyenda («mejora» ↑, «empeora» ↓). Ahora la flecha
sigue al veredicto: arriba si mejora, abajo si empeora; el signo del texto dice si el valor
subió o bajó.
Nuevo InfoTip (icono «i» con explicación al pasar el ratón, con el foco del teclado o al
tocar; se cierra con Escape o al tocar fuera). Se pinta en un portal y con posición fija, para
que las tarjetas (overflow y container queries) no la recorten, y se empuja hacia dentro si
está en un borde.

Explica: las cuatro métricas (qué mide y si más o menos es mejor), las clases de datos, las
semillas, la etiqueta oracle/sembrados, «con otras semillas», el veredicto y «De un vistazo».
Sustituye los title nativos de esas etiquetas.
…ta de nivel

Se mantienen los de las métricas, el selector de clases de datos y «De un vistazo».
…ismo commit

Las barras de causas de fallo usaban el nombre de la ejecución (el commit) como key de React, y
dos ejecuciones del mismo commit lo comparten: «Encountered two children with the same key».
Ahora la key es el id de la ejecución.
…d-evolucion

Conflicto en Live con el arreglo de dev del aviso de conexión perdida. Se conserva el de dev
(descartar episodios abiertos más de 15 min) y se mantiene la separación de esta rama entre
conexión perdida y episodio sin datos, con el umbral holgado de dev como justificación.
AGENTS.md conserva las dos líneas de estado.
Copilot AI lite review requested due to automatic review settings September 19, 2026 19:11
@AnderVarela
AnderVarela merged commit 1db3375 into dev Sep 19, 2026
5 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

VerdictRow cancela siempre el comportamiento del enlace al hacer click, bloqueando acciones estándar (Ctrl/Cmd‑click/rueda) y contradiciendo su propia intención documentada.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

Este PR convierte Resumen de evolución en la pantalla principal (/) para visualizar, por tarea y nivel, la evolución de métricas de v_run_summary, y mueve Live a /live. Además, refuerza la lectura de cambios (mejora/empeora), añade componentes reutilizables (tendencias, ayudas y selectores) y corrige detalles de Live y de la comparativa.

Changes:

  • Nueva pantalla Resumen/Evolución como landing (/) con selector de clase de datos y panel lateral “De un vistazo”.
  • Live distingue conexión perdida vs episodio sin datos (silencio con canal sano) y evita arrastrar marcas de señal entre episodios.
  • Mejora de UX en detalle/comparativa: selector “Esquema | Captura”, capturas como tarjeta, rellenos opacos en el palé y fix de keys duplicadas en comparativa.
File Description
frontend/​styles/​colors.css Ajusta fills del palé a mezcla opaca con --surface para consistencia con la leyenda.
frontend/​lib/​ui.ts Añade helpers de UI (changeTone, capitalize, shortDate).
frontend/​lib/​routes.ts Centraliza nuevas rutas: dashboard: "/" y live: "/live".
frontend/​components/​screens/​LiveScreen/​useLiveScreen.ts Integra nueva lógica de “staleness” y canal error desde Realtime.
frontend/​components/​screens/​LiveScreen/​LiveScreen.tsx Muestra banners diferenciando “silent” vs “lost”.
frontend/​components/​screens/​LiveScreen/​LiveScreen.helper.ts Modela Staleness y la detección de “lost/silent”.
frontend/​components/​screens/​DashboardScreen/​useDashboardScreen.ts Nuevo hook para estado del Resumen, kind y secciones.
frontend/​components/​screens/​DashboardScreen/​index.ts Barrel export de DashboardScreen.
frontend/​components/​screens/​DashboardScreen/​DashboardScreen.tsx Nueva pantalla principal “Evolución” con rail lateral y ayudas.
frontend/​components/​screens/​DashboardScreen/​DashboardScreen.module.css Layout sticky + scroll interno para Resumen.
frontend/​components/​screens/​DashboardScreen/​DashboardScreen.helper.ts Construye secciones por tarea/nivel y gestión de kinds.
frontend/​components/​screens/​AppHeader/​AppHeader.helper.ts Ajusta pestaña activa con rutas dashboard/live/runs.
frontend/​components/​organisms/​TopBar/​TopBar.tsx Añade pestaña “Resumen” y usa routes.*.
frontend/​components/​organisms/​TopBar/​TopBar.module.css Ajustes responsive para 3 pestañas.
frontend/​components/​organisms/​TaskSection/​TaskSection.tsx Nueva sección por tarea con anchors por nivel.
frontend/​components/​organisms/​TaskSection/​TaskSection.module.css Estilos y scroll-margin-top para navegación desde el rail.
frontend/​components/​organisms/​TaskSection/​index.ts Barrel export de TaskSection.
frontend/​components/​organisms/​OverviewPanel/​OverviewPanel.tsx Nuevo panel lateral “De un vistazo” con navegación a anchors.
frontend/​components/​organisms/​OverviewPanel/​OverviewPanel.module.css Estilos del panel lateral.
frontend/​components/​organisms/​OverviewPanel/​OverviewPanel.helper.ts Scroll interno a anchors via scrollIntoView.
frontend/​components/​organisms/​OverviewPanel/​index.ts Barrel export de OverviewPanel.
frontend/​components/​organisms/​LevelCard/​LevelCard.tsx Nueva tarjeta por nivel con métricas + tendencias.
frontend/​components/​organisms/​LevelCard/​LevelCard.module.css Grid responsive por container queries para mosaicos de métricas.
frontend/​components/​organisms/​LevelCard/​LevelCard.helper.ts Construye series/curvas, comparabilidad, veredictos y tooltips.
frontend/​components/​organisms/​LevelCard/​index.ts Barrel export de LevelCard y helpers.
frontend/​components/​organisms/​index.ts Reexporta nuevos organismos (LevelCard/TaskSection/OverviewPanel).
frontend/​components/​organisms/​EpisodeDashboard/​EpisodeDashboard.tsx Sustituye botón por selector “Esquema
frontend/​components/​organisms/​CompareResult/​CompareResult.tsx Evita keys duplicadas usando key estable en barras.
frontend/​components/​organisms/​ComparePanel/​ComparePanel.helper.ts Reutiliza changeTone y añade key: run.id a barras.
frontend/​components/​molecules/​VerdictRow/​VerdictRow.tsx Nueva fila enlazable con veredicto y detalle.
frontend/​components/​molecules/​VerdictRow/​VerdictRow.module.css Estilos de la fila de veredicto.
frontend/​components/​molecules/​VerdictRow/​index.ts Barrel export de VerdictRow.
frontend/​components/​molecules/​SnapshotView/​SnapshotView.tsx Convierte captura en “tarjeta” con ratio controlado.
frontend/​components/​molecules/​SnapshotView/​SnapshotView.module.css Layout con container queries de tamaño y tag superpuesto.
frontend/​components/​molecules/​SegmentedControl/​SegmentedControl.tsx Nuevo control segmentado accesible basado en radios.
frontend/​components/​molecules/​SegmentedControl/​SegmentedControl.module.css Estilos del segmented (normal y compacto).
frontend/​components/​molecules/​SegmentedControl/​index.ts Barrel export de SegmentedControl.
frontend/​components/​molecules/​PanelHeader/​PanelHeader.module.css Ajusta padding y wrap para headers con controles.
frontend/​components/​molecules/​NavTab/​NavTab.module.css Ajustes responsive para tabs en móvil.
frontend/​components/​molecules/​MetricTrend/​MetricTrend.tsx Nuevo mosaico de métrica: valor, cambio y curva.
frontend/​components/​molecules/​MetricTrend/​MetricTrend.module.css Estilos del mosaico de métrica.
frontend/​components/​molecules/​MetricTrend/​index.ts Barrel export de MetricTrend.
frontend/​components/​molecules/​InfoTip/​InfoTip.tsx Nuevo tooltip con portal + posición fija y seguimiento al scroll.
frontend/​components/​molecules/​InfoTip/​InfoTip.module.css Estilos del tooltip y trigger.
frontend/​components/​molecules/​InfoTip/​InfoTip.helper.ts Cálculo de posición del tooltip en viewport.
frontend/​components/​molecules/​InfoTip/​index.ts Barrel export de InfoTip.
frontend/​components/​molecules/​index.ts Reexporta nuevos molecules (SegmentedControl, MetricTrend, InfoTip, etc.).
frontend/​components/​molecules/​ChangePill/​index.ts Barrel export de ChangePill.
frontend/​components/​molecules/​ChangePill/​ChangePill.tsx Badge con flecha/dirección y tono para “mejora/empeora/igual”.
frontend/​components/​molecules/​ChangeLegend/​index.ts Barrel export de ChangeLegend.
frontend/​components/​molecules/​ChangeLegend/​ChangeLegend.tsx Leyenda “Cómo leerlo” para interpretar flechas/signos.
frontend/​components/​molecules/​ChangeLegend/​ChangeLegend.module.css Estilos de la leyenda.
frontend/​components/​atoms/​Trend/​Trend.tsx Nuevo SVG de tendencia con baseline y dots.
frontend/​components/​atoms/​Trend/​Trend.module.css Estilos del SVG de tendencia (ok/bad/muted, dashed, dots).
frontend/​components/​atoms/​Trend/​Trend.helper.ts Genera geometría/path/dots para series con nulls.
frontend/​components/​atoms/​Trend/​index.ts Barrel export de Trend.
frontend/​components/​atoms/​index.ts Reexporta Trend y TrendPoint.
frontend/​components/​atoms/​Icon/​Icon.tsx Añade iconos arrowUp, minus, info y expande IconName.
frontend/​components/​atoms/​Badge/​Badge.tsx Añade tono warn.
frontend/​components/​atoms/​Badge/​Badge.module.css Estilos para warn (color + fill).
frontend/​app/​page.tsx / pasa a renderizar DashboardScreen.
frontend/​app/​live/​page.tsx Nueva ruta /live para LiveScreen.
frontend/​api/​hooks/​useEpisodeRealtime.ts Señal por episodio + channelError para distinguir “lost” vs “silent”.
AGENTS.md Actualiza estructura/rutas y documenta el nuevo Resumen.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +21 to +22
<a href={href} className={styles.row}
onClick={onSelect && ((e) => { e.preventDefault(); onSelect(); })}>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants