Spaces:
Sleeping
CI: puerta de código en todos los PR (ruff, pytest, tsc, eslint)
Browse filesAntes, un PR que tocara sólo `backend/app/security/` o `backend/app/routers/` no
disparaba NINGÚN workflow: el único que existía filtraba por rutas y nombraba
`backend/app/ai/**` y `backend/app/rag/**`. Toda la superficie de autenticación,
sesiones, CSRF e ingesta de laboratorio se fusionaba sin que nadie ejecutara
`backend/tests/`, que nunca ha corrido en CI pese a estar en `make backend-test`.
`ci.yml` corre en todos los PR, sin filtro: ruff + pytest (backend) y tsc --noEmit
+ eslint (frontend). El alcance de ruff es el de `make lint` (evals/ y bridge/
fuera a propósito). Sin `--group rag`: las dos suites que lo necesitan ya se
auto-omiten y los grupos pesados costarían GBs por una prueba sintética.
`evals.yml` conserva su filtro —es la puerta cara— pero se amplía a `backend/**`
y `frontend/**`: el anterior dejaba fuera `schemas.py`, que define la forma misma
que las evals puntúan, y `config.py`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- .github/workflows/ci.yml +59 -0
- .github/workflows/evals.yml +18 -5
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: ci
|
| 2 |
+
|
| 3 |
+
# Puerta de calidad del CÓDIGO (rápida). La puerta clínica —motor determinista y evals— vive
|
| 4 |
+
# en `evals.yml`, que sí filtra por rutas porque su coste es otro.
|
| 5 |
+
#
|
| 6 |
+
# Este workflow NO lleva filtro `paths` a propósito: antes, un PR que tocara sólo
|
| 7 |
+
# `backend/app/security/` o `backend/app/routers/` no disparaba NINGÚN workflow, así que toda
|
| 8 |
+
# la superficie de autenticación, sesiones, CSRF y ingesta de laboratorio se fusionaba sin que
|
| 9 |
+
# nadie ejecutara `backend/tests/`. Cualquier PR corre esto.
|
| 10 |
+
|
| 11 |
+
on:
|
| 12 |
+
pull_request:
|
| 13 |
+
push:
|
| 14 |
+
branches: [main]
|
| 15 |
+
|
| 16 |
+
jobs:
|
| 17 |
+
backend:
|
| 18 |
+
runs-on: ubuntu-latest
|
| 19 |
+
steps:
|
| 20 |
+
- uses: actions/checkout@v4
|
| 21 |
+
- uses: astral-sh/setup-uv@v5
|
| 22 |
+
with:
|
| 23 |
+
enable-cache: true
|
| 24 |
+
- name: Sincronizar backend
|
| 25 |
+
working-directory: backend
|
| 26 |
+
# Sin `--group rag`: los grupos pesados son opt-in (ver pyproject) y las dos suites que
|
| 27 |
+
# dependen de LanceDB/sentence-transformers ya se auto-omiten
|
| 28 |
+
# (`test_retriever_integracion.py`, `test_alcance_corpus.py`). Instalarlos aquí añadiría
|
| 29 |
+
# GBs y minutos a cambio de una prueba de integración sintética. Si algún día la
|
| 30 |
+
# recuperación regresa sin que nadie se entere, ese es el momento de añadirlos.
|
| 31 |
+
run: uv sync
|
| 32 |
+
- name: Ruff (backend + scripts)
|
| 33 |
+
working-directory: backend
|
| 34 |
+
# Mismo alcance que `make lint`: evals/ y bridge/ quedan fuera a propósito, aún no
|
| 35 |
+
# están saneados bajo estas reglas.
|
| 36 |
+
run: uv run ruff check . ../scripts
|
| 37 |
+
- name: Pruebas del backend
|
| 38 |
+
working-directory: backend
|
| 39 |
+
run: uv run pytest -q
|
| 40 |
+
|
| 41 |
+
frontend:
|
| 42 |
+
runs-on: ubuntu-latest
|
| 43 |
+
steps:
|
| 44 |
+
- uses: actions/checkout@v4
|
| 45 |
+
- uses: actions/setup-node@v4
|
| 46 |
+
with:
|
| 47 |
+
node-version: "22"
|
| 48 |
+
cache: npm
|
| 49 |
+
cache-dependency-path: frontend/package-lock.json
|
| 50 |
+
- name: Instalar frontend
|
| 51 |
+
working-directory: frontend
|
| 52 |
+
run: npm ci
|
| 53 |
+
- name: Tipos (tsc --noEmit)
|
| 54 |
+
working-directory: frontend
|
| 55 |
+
# `npm run build` ya lo corría, pero nada ejecutaba el build en CI.
|
| 56 |
+
run: npm run typecheck
|
| 57 |
+
- name: ESLint
|
| 58 |
+
working-directory: frontend
|
| 59 |
+
run: npm run lint
|
|
@@ -1,14 +1,20 @@
|
|
| 1 |
name: evals
|
| 2 |
|
| 3 |
-
# Puerta de calidad: bloquea el merge si el motor determinista regresa o si la suite
|
| 4 |
-
# de evaluación
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
on:
|
| 7 |
pull_request:
|
| 8 |
paths:
|
| 9 |
-
- "frontend/
|
| 10 |
-
- "backend/
|
| 11 |
-
- "backend/app/rag/**"
|
| 12 |
- "evals/**"
|
| 13 |
- "data/**"
|
| 14 |
push:
|
|
@@ -44,6 +50,13 @@ jobs:
|
|
| 44 |
- name: Instalar deps del motor (para el puente Node)
|
| 45 |
working-directory: frontend
|
| 46 |
run: npm ci
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
# En CI real, sustituir --simular por --modelo medgemma apuntando a un endpoint,
|
| 48 |
# o subir un archivo de predicciones generado en un job con GPU.
|
| 49 |
#
|
|
|
|
| 1 |
name: evals
|
| 2 |
|
| 3 |
+
# Puerta de calidad CLÍNICA: bloquea el merge si el motor determinista regresa o si la suite
|
| 4 |
+
# de evaluación cae bajo sus umbrales o registra violaciones de seguridad.
|
| 5 |
+
#
|
| 6 |
+
# Este sí filtra por rutas —es el workflow caro— pero el filtro anterior era demasiado
|
| 7 |
+
# estrecho: nombraba `backend/app/ai/**` y `backend/app/rag/**`, dejando fuera `schemas.py`
|
| 8 |
+
# (que define `InterpretacionClinica`, la forma misma que las evals puntúan) y `config.py`
|
| 9 |
+
# (umbrales y ruta de modelo por defecto). Un cambio ahí alteraba la salida evaluada sin
|
| 10 |
+
# disparar la puerta. Las puertas de código —ruff, pytest, tsc, eslint— viven en `ci.yml`,
|
| 11 |
+
# que corre en TODOS los PR sin filtro.
|
| 12 |
|
| 13 |
on:
|
| 14 |
pull_request:
|
| 15 |
paths:
|
| 16 |
+
- "frontend/**"
|
| 17 |
+
- "backend/**"
|
|
|
|
| 18 |
- "evals/**"
|
| 19 |
- "data/**"
|
| 20 |
push:
|
|
|
|
| 50 |
- name: Instalar deps del motor (para el puente Node)
|
| 51 |
working-directory: frontend
|
| 52 |
run: npm ci
|
| 53 |
+
# Antes de la puerta, la puerta misma: métricas, rúbrica, umbrales y esquema del dataset
|
| 54 |
+
# son código sin cobertura de nadie más. Si el medidor está roto, el resultado de la
|
| 55 |
+
# puerta no significa nada (visto: el simulador dejaba `fuera_de_alcance` sin declarar y
|
| 56 |
+
# suspendía una métrica de tolerancia cero por su cuenta).
|
| 57 |
+
- name: Pruebas unitarias de los scripts de evals
|
| 58 |
+
working-directory: backend
|
| 59 |
+
run: uv run pytest -q ../evals/tests
|
| 60 |
# En CI real, sustituir --simular por --modelo medgemma apuntando a un endpoint,
|
| 61 |
# o subir un archivo de predicciones generado en un job con GPU.
|
| 62 |
#
|