Spaces:
Sleeping
Sleeping
Commit History
-
Los cortes IRIS también pasan a data/ajustes_clinicos.json
Jose Salazar +1: Claude Opus 5Cierra lo que quedaba de §4.6 en el motor: `CORTES_IRIS_CREAT`, `CORTES_IRIS_SDMA` y `CORTES_IRIS_UPC` eran las últimas reglas clínicas incrustadas en el código. No había duplicación que eliminar —el estadiaje es sólo del cliente, no hay contraparte en Python— así que el motivo aquí es únicamente el que dio origen a todo esto: son decisiones clínicas que un veterinario debería poder revisar y ajustar sin desarrollador ni build. Los cortes de la guía IRIS se revisan periódicamente (la tabla vigente es la modificada en 2026); tenerlos en TypeScript convertía una actualización de guía en un cambio de código. Viaja con ellos su procedencia (guía IRIS 2026 / Fundamentals 3.a ed., p. 573, Tabla 8.4) y, en `_limitacion`, la nota de por qué el motor sólo estadia cuando creatinina o SDMA salen de rango: la guía estadia pacientes YA diagnosticados de ERC sobre muestras seriadas, y aquí sólo hay una analítica suelta. Los 5 tests dorados del bloque IRIS —estadiaje por creatinina, escalada por S…e6acd07 -
Las reglas clínicas del suelo de seguridad pasan a data/ajustes_clinicos.json
Jose Salazar +1: Claude Opus 5El puerto Python del suelo (§1.1) dejaba dos implementaciones de las mismas reglas. Pero lo que se desincroniza no es la LÓGICA —multiplicar límites, comparar, clasificar; eso no cambia casi nunca— sino los VALORES: umbrales de gravedad, cortes explícitos, factores por edad y raza. Son además lo único que un veterinario querría tocar, y hasta ahora exigían un desarrollador y un build. Se extraen a `data/ajustes_clinicos.json`, que leen los dos motores: `analisis.ts` por fetch (como valores_referencia.json), `motor/gravedad.py` de disco y `evals/engine_runner.ts` de disco. Quedan 0 constantes clínicas duplicadas en ambos motores; lo que permanece es la lógica de aplicarlas. Se carga en runtime y NO se empaqueta en el bundle: un `import` de JSON lo inlinearía en tiempo de build y editar el fichero dejaría de tener efecto sin recompilar, que es exactamente lo que esto viene a evitar. También se mueven los límites de las categorías de edad: que «senior» empiece a los 7 años es una decis…5b69117 -
El suelo de seguridad se recalcula en el servidor
Jose Salazar +1: Claude Opus 5ARCHITECTURE_REVIEW §1.1. El motor determinista del que depende toda la historia de seguridad corre en el NAVEGADOR, y el backend aceptaba su veredicto como un hecho: los `hallazgos` llegaban como campos de la petición y el docstring del esquema lo decía por escrito («El backend NO recalcula»). Un cliente que mandara `hallazgos: []` desactivaba de una sola petición el suelo de derivación obligatoria y la detección de analitos fabricados. No hacía falta un ataque —era el contrato documentado de la API— y bastaba un bundle cacheado de ayer para que el servidor aplicara una seguridad distinta de la que creía aplicar. QUÉ SE PORTA. Sólo lo que sostiene el suelo: rangos ajustados por edad y raza, y clasificación de gravedad (~250 líneas de las 1062). La detección de patrones se queda en el cliente porque ninguna decisión de seguridad cuelga de ella; portarla habría creado una segunda implementación del motor validado por veterinario. Se descartó meter Node en la imagen de producción: depen…c205c6b -
Cerrar el alta de cuentas y apagar la cola de muestras por defecto
Jose Salazar +1: Claude Opus 5Contención inmediata de ARCHITECTURE_REVIEW §2.2 y §2.1. Ninguna de las dos es el arreglo estructural —ese es el scoping por tenant— pero ambas reducen hoy la superficie sin tocar el modelo de datos. ALTA CERRADA (§2.2). Cualquiera podía POSTear /api/auth/registro y alcanzar /api/interpret, que gasta cuota de ZeroGPU compartida y, por la ruta Claude, dinero real: `limite_interpret_usuario` era un techo sobre una identidad que costaba una petición HTTP acuñar. Ahora `registro_abierto=False` + `registro_allowlist`. Dos detalles que no son cosméticos: - La comprobación de allowlist va ANTES que la de existencia. Al revés, un email no aprobado distinguiría 409 (existe) de 403 (no existe) y el alta sería un oráculo de la base de usuarios. Fuera de la lista: 403 siempre. - Es una lista de emails y no un booleano porque `instance/` es efímero (§3.4): las cuentas desaparecen en cada reinicio, así que un alta cerrada sin lista dejaría la instancia sin acceso posible. Se avisa al arran…61cd0db -
pdf.js 4.x vendorizado y pruebas del extractor de PDF
Jose Salazar +1: Claude Opus 5La 3.x leía mal los CMap `ToUnicode` con destinos de un byte —fuera de especificación, pero los emiten informes de laboratorio reales generados con Ghostscript— y devolvía cada carácter desplazado 8 bits ('H' → U+4800), con lo que la importación fallaba entera con «No se encontraron datos reconocibles». El desplazamiento NO se puede reparar a posteriori: el '0' desplazado cae en U+3000 y el extractor lo normaliza a espacio, así que una ALT de 260 U/L se leería como 26. Por eso `textoIlegible()` detecta el caso y aborta en vez de importar números equivocados. pdf.js 4+ se distribuye como módulo ES y ya no publica `window.pdfjsLib`, de ahí el paso de .js a .mjs y la carga dinámica. La versión es un invariante: los ficheros de `assets/lib/pdfjs/` se copian de la devDependency con `npm run vendor-pdfjs` para que navegador y pruebas usen la misma. `frontend/tests/pdf-parser.test.ts` fija todo esto con un PDF construido con esa anomalía, y cubre la ventana de aceptación de valores: sólo en…c0b119e -
Estado vacío de los paneles de exámenes en escritorio
Jose Salazar +1: Claude Opus 5`panel-vacio.ts` sustituye el formulario por una zona de adjuntar (arrastrar / explorar / «Insertar resultados manualmente») mientras el `<section>` lleva la clase `.sin-datos`. Sólo en escritorio: el CSS que lo enciende vive dentro de `@media (min-width: 1101px)`. Depende sólo de `dom.ts` (`esGridEscritorio`, extraído ahí para que lo compartan `ui.ts`, `lab-import.ts` y este módulo). Lo importa `form-inject.ts`, base común de los dos importadores, que llama a `revelarPanelDeCampo()` por cada valor inyectado: un panel que recibe datos sale del estado vacío solo. Colgarlo de `ui.ts` —que toca el DOM al cargarse— rompería sus pruebas. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>e4a79ec -
Léxico clínico compartido y detección de analitos fabricados
Jose Salazar +1: Claude Opus 5`ai/lexico.py` centraliza el vocabulario clínico (variantes, abreviaturas, nombres) que hasta ahora vivía disperso, y `ai/coherencia.py` lo usa para la comprobación que faltaba: distinguir «no se midió» de «se midió y salió en rango». Sin ese dato el modelo rellenaba el hueco —medido el 2026-08-04: medGemma afirmó un leucograma con neutrofilia sobre un panel de calcio/fósforo/ BUN/creatinina, y llamó «trombocitopenia leve» a unas plaquetas en rango—. De ahí `analitos_medidos` en `PeticionInterpretacion` y en el cliente (`ia.ts`): el panel COMPLETO, no sólo lo alterado. Campo opcional, así que un cliente antiguo que no lo mande se comporta como antes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>7dba92c
-
Agrego boton para el syncing de dispositivos de laboratorio en la UI de desktop
Jose Salazar1fec72e -
Allow list para modelos locales configurables por el usuario
Jose Salazar6ab7946 -
Ajustes varios al engine y al prompt basado en resultados de los evals
Jose Salazarbf9f7d1
-
Implementacion de AI judge para evals y actualizacion de readme
Jose Salazar1e215c9
-
Añadir el stack nuevo: Vite/TypeScript + FastAPI
Jose Salazar +1: Claude Opus 5frontend/ Motor de patrones portado a TS (analisis.ts) con 27 tests dorados que fijan el comportamiento validado por veterinarios, más el resto de módulos (ui, pdf-parser, auth, papers, lab-import, ia). backend/ Servicio FastAPI: salida estructurada con Pydantic, clientes medGemma/Claude, recuperación RAG y toda la seguridad (sesión, CSRF, rate limit, CORS cerrado, BD fuera del webroot). bridge/ Puente local ASTM/HL7 para analizadores de laboratorio. evals/ Arnés de evaluación clínica + puerta de CI. index.html pasa a cargar el bundle TS en lugar de js/main.js. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>70e641d