Elaizii por dentro

Escrito el 05/11/2026 11:48 CET · Silicio · Karb and Sil · CC BY 4.0 (el texto; los datos, la licencia de cada fuente).

Esta es la puerta de entrada a cómo funciona Elaizii hoy: cómo es, por qué es así y dónde mirar. Lo que cuenta el día a día de los cuarenta y pico encargos (E-1361 … E-1578, trabajo TX-1362) está en [elaizii-en-la-red.md](elaizii-en-la-red.md), que es la historia, en orden; esto es la foto de hoy. Público: interno (Silicio, los agentes, Eduardo).

Las cifras de este documento se midieron sobre la copia de producción de la mesa (/datos/nvme/elaizii/produccion/mesa.sqlite, abierta en solo lectura, mode=ro) en la nave el 05/11/2026 11:43 CET. La mesa pesa 10,7 GB y su última capa en producción (capa_profarmaco, E-1566) corrió el 05/11/2026 10:17. Las consultas usadas están en § 9.

Diagramas (Archify, validados «showcase»): arquitectura · de las fuentes a la mesa · una pregunta, paso a paso · encargo → recogida → despliegue.


1. Qué es Elaizii y qué contesta

Elaizii es un grafo clínico que se pregunta en lenguaje natural. Reúne, en una sola red consultable, los grandes vocabularios médicos abiertos (SNOMED CT, CIMA, LOINC, Orphanet, HPO, MeSH/DeCS, ClinVar, ChEBI, ChEMBL, los genes de HGNC y Gene Ontology, MONDO, la UMLS, la parte médica de Wikidata y la literatura de PubTator), unidos por código exacto, nunca por parecido del nombre. Hoy tiene 2,01 millones de objetos vigentes y 5,9 millones de relaciones (§ 9).

Tres puertas, un mismo grafo detrás:

  • La web [elaizii.com](https://elaizii.com) (repo webs/elaizii, estática en Cloudflare): caja para preguntar, el explorador de fichas, el semáforo de congestión y el pie «Fuentes y licencias» (tomado de la API, no copiado a mano).
  • La API [elaizii-api.wordkers.com](https://elaizii-api.wordkers.com) (contenedor elaizii-api en la nave, tras Caddy): Flask/gunicorn, de solo lectura, con el aviso legal de SNOMED en cada respuesta. Operaciones en [docs/operaciones.md](operaciones.md). Comprobado el 05/11/2026 11:43: /health responde (555 030 conceptos SNOMED), /v1/elaizii/estado en verde.
  • El MCP https://elaizii-api.wordkers.com/mcp (HTTP streamable, SDK oficial), para que un agente pregunte con las mismas herramientas. Ficha en [docs/mcp.md](mcp.md).

Quien contesta es Syd 🕸️ (Cypher): un modelo barato (DeepSeek deepseek-v4-flash) que no sabe medicina, solo se fía del grafo, y cada afirmación la respalda un hecho que vio. Syd ya no tiene bucle propio: es una configuración de la red de Elaizii para el respondedor común (dev/grafo red/respondedor.py). Ver § 6 y [docs/syd.md](syd.md) (ese doc describe el Syd anterior, con bucle y recetas; lo vigente es § 6 de esta página).

Comprobado el 05/11/2026: «¿para qué sirve el dabigatrán?» → «Según ChEMBL, el dabigatrán está indicado (aprobado) para: fibrilación auricular, embolia, accidente cerebrovascular… Estas indicaciones llegan a través de sus formas/sales con que se receta (Dabigatran etexilate…). Aparte, solo en investigación…» (forma para_que_sirve, traza buscar→relaciones→ relaciones, DeepSeek).


2. Las fuentes

Dieciocho fuentes dejan hechos en la mesa de producción hoy (§ 9 da los recuentos). Cada lector por lotes vive en dev/grafo red/<fuente>.py y baja la fuente a un snapshot local en la nave (/datos/nvme/elaizii/<fuente>.sqlite); la capa de [grafo/a_mesa.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/grafo/a_mesa.py) la pone en la mesa. Lo nuestro (uniones, relaciones deducidas, los 79 tipos de 2018) es CC BY 4.0; cada fuente conserva su licencia en cada hecho, y el aviso que pide sale del hecho ([avisos.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/avisos.py) + [red/consultas.py](https://gitlab.com/wordkers/dev/grafo/-/blob/main/red/consultas.py) CITAS/ATRIBUCIONES), nunca pegado a mano.

FuenteQué aportaSnapshot / dónde viveLicencia
SNOMED CT (ed. española RF2, es-20260901)el armazón: conceptos, jerarquía «es un», atributos, mapas a CIE-10 y a Orphanetbase snomed del Postgres de la nave; vistas, no se copiasnomed (afiliado SNS) · no sale de la nave
CIMA (AEMPS)medicamentos y principios activos españoles, ATC, forma, víacima.sqliteaemps (© AEMPS, sin modificar; permiso 29/10/2026)
LOINC (Regenstrief, 2.83, con es-ES)análisis y observaciones de laboratorio y sus seis ejesloinc.sqlite + ficheros en /datos/nvme/elaizii/loinc/loinc · no sale de la nave
Orphanet (Orphadata, 1.3.42)enfermedades raras, su jerarquía y sus alineamientosorphanet.sqliteCC BY 4.0
HPO (2026-09-01)fenotipos (síntomas y signos) y enfermedad → fenotipo, en españolhpo.sqlitehpo (no alterable)
MeSH (NLM, 2026)el vocabulario de la NLM y su árbol; el puente con DeCSmesh.sqliteNLM (dominio público con reconocimiento)
DeCS (OPS/BIREME)MeSH en español (nombres sobre los mesh:) y descriptores propioslee el XML directo (sin snapshot)decs (acuerdo BIR-267-26) · no sale de la nave, no va a la estantería común
ClinVar (NCBI, 2026-10-26)gen → enfermedad, con significado clínico y estrellasclinvar.sqliteNCBI (dominio público con reconocimiento; no es para diagnóstico)
ChEBI (EMBL-EBI, v256)las sustancias químicas de referencia, su jerarquía y su rolchebi.sqliteCC BY 4.0
ChEMBL (EMBL-EBI, 37)indicaciones: fármaco → enfermedad, con la fase de ensayochembl-*.sqliteCC BY-SA 3.0
HGNC (2026-10-27)nombres oficiales de los genes humanos y sus familiashgnc.sqliteCC0
Gene Ontology (2026-07-26)qué hace cada gen (función, proceso, lugar)go.sqliteCC BY 4.0
MONDO (Monarch, 2026-10-06)el puente que casa los catálogos de enfermedadmondo.sqliteCC BY 4.0
UMLS (NLM, 2026AA)el CUI como puente entre fuentes (nunca su texto)umls.sqlite (de MRCONSO.RRF, 2,3 GB) · no sale de la naveNLM (licencia UTS)
Wikidata médicalos puentes por código entre casi todas las fuentes (CC0)wd-medica.sqlite (+ acotados por capa)CC0
PubTator3 (NLM)lo que dice la literatura (extracción automática), aparte de lo curadopubtator.sqlite (de relation2pubtator3.gz)dominio público
ComplexPortalcomplejos de proteínas y sus componentesdentro del snapshot de genesCC0
CIE-10los códigos (la pirámide), por los mapas de SNOMEDse deriva de SNOMEDsnomed (los nombres los pondrá el Ministerio)

Fuera, por decisión o por licencia (§ 10): OMIM (su acuerdo prohíbe distribuir), los nombres ATC de la OMS (de pago / no comercial; los códigos sí entran por CIMA), y las fuentes de categoría 3 de la UMLS (CIE-10 de la OMS, MedDRA).


3. La mesa

Elaizii no pregunta a la estantería común (red) ni a SNOMED directamente: pregunta a una mesa, un SQLite de solo lectura con exactamente el esquema de la mesa común (dev/grafo red/mesa.sql, que se lee de ahí, no se copia). Así el respondedor común le habla a esta mesa con las mismas herramientas que a las efemérides o al fútbol: un grafo para quien pregunta. SNOMED se queda al lado (decisión [1] de Eduardo, 28/10/2026): su base no sale de la nave y se mira por vistas; lo nuestro (CC BY) va a la estantería; la mesa junta las dos.

Dos ficheros, y por qué.

  • La mesa de trabajo /datos/nvme/elaizii/mesa.sqlite: donde escriben los encargos (a_mesa.py --solo-…). Puede quedar a medias mientras se construye.
  • La copia de producción /datos/nvme/elaizii/produccion/mesa.sqlite: la que sirve elaizii-api, montada de solo lectura ([deploy/run.sh](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/deploy/run.sh) monta la carpeta, no el fichero, porque a_mesa.py reemplaza el fichero con os.replace). Se pone al día solo al recoger un encargo, con sus tests en verde. El 29/10/2026 un encargo cargó a medias en la de trabajo y producción dejó de encontrar la glucosa y el ATC: de ahí la copia fija (ver la cabecera de deploy/run.sh).

El esquema (común, nueve tablas más el precálculo). En entidad-relación detallado: [docs/mesa-er.md de dev/grafo](https://gitlab.com/wordkers/dev/grafo/-/blob/main/docs/mesa-er.md) y las fuentes en [docs/fuentes-er.md](fuentes-er.md). En llano:

  • **objeto — el nodo mudo**: un id con prefijo de vocabulario (sct:, cima:, loinc:, orpha:, hp:, mesh:, hgnc:, go:, chebi:, chembl:, mondo:, cie10:, wd:, valor…) y un tipo (hallazgo, sustancia, fármaco, gen, análisis…). vigente: lo inactivo no se borra, caduca.
  • **apuntador — los nombres** (cada nombre con su lengua, registro, entra para buscar y sale para mostrarse: así «golondrino» entra pero sale «hidrosadenitis supurativa»). El concepto es el mismo en todas las lenguas; solo cambian las etiquetas ([docs/modelo.md](modelo.md)).
  • **relacion** — la arista, con su tipo_objeto (que también es un objeto), su marco (JSON con lo que la frase dice de ella), su hecho (la clave que la justifica), su regla (que es a la vez su lote deshacible) y su vigente.
  • **hecho — la frase** que respalda una relación, con fuente, revision y **licencia**. SNOMED no trae frases: se le genera «A —tipo→ B».
  • **fusion — dos objetos que las reglas dicen que son el mismo** (p. ej. wd:Q… ↔ sct:… por P5806). Nada se borra: una fusión retirada va a vigente=0.
  • **grupo / grupo_info (precálculo, E-1487) — las fusiones ya resueltas en grupos: cada grupo es un objeto para quien pregunta y lo representa** su sct: si lo hay (preferencia sct:, luego wd:). Sin esto, «paracetamol» (la sustancia SNOMED) no vería los medicamentos de CIMA, que cuelgan del mismo grupo.
  • **cuestion — las contradicciones abiertas (dos destinos para una fusión, un ciclo, un candidato por nombre sin segunda señal): no se fusiona, se pregunta**. Hoy hay 24 289 abiertas.
  • **sentido, aportacion, meta — el puente con la capa de lengua (vacío aún), lo que pide el constructor, y las cifras y los manifiestos de los lotes** (meta lleva lote:*, deshacer:*, lotes).
  • Precálculo (E-1487): nivel (profundidad por «es un») y cuenta (totales por grupo/tipo/dirección) se calculan al construir y en cada rehacer_*, para que nunca queden desfasados. La mesa crece ~15 % y abrir va 3,9× más rápido.

Un grupo de fusión y su representante. Un principio activo como el ketoprofeno puede llegar como sct: (SNOMED), cima:pa: (CIMA), chebi: (ChEBI), wd:/mesh:/chembl: (la química): si las reglas prueban que son el mismo, caen en un solo grupo, y Syd lo ve como un objeto con todas sus identidades. La regla de oro: cada identidad va al grupo que le toca (la sustancia química a la sustancia, no al producto), y **nunca dos sct: en un grupo** (§ 5).


4. Las capas, en orden

La mesa se construye en [grafo/a_mesa.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/grafo/a_mesa.py) (construir), capa a capa, siempre en el mismo orden: cada una lee lo que dejaron las anteriores. Cada capa se puede rehacer sola (--solo-…, copia la mesa con fecha antes) y la mayoría deja un lote deshacible. Esta es la cadena viva hoy (el recuento es de producción, 05/11/2026, § 9; donde no lo medí va el del informe de su encargo, marcado (informe)):

#CapaEncargo--solo-…Qué hace / regla
1SNOMEDE-1365(base)conceptos sct:, su jerarquía «es un», atributos y nombres es/en; 555 030 conceptos
2CIE-10E-1377, E-1482--solo-cie10por los mapas de SNOMED (refset 447562003): cie10: como relación «se codifica en CIE-10 como» (no fusión), la pirámide por el código (E78.0 «es un» E78) y el mapa condicional
3WikidataE-1378, E-1438--solo-wikidatael wd: médico y todos sus identificadores como puentes por código; fusión wd:↔sct: por P5806
4OrphanetE-1382, E-1478--solo-orphanetenfermedades raras, jerarquía, alineamientos; fusión orpha:↔wd: por P1550; estado de cada enfermedad
5genesE-1389, E-1521--solo-geneshgnc: (+ familias), términos go: y sus anotaciones; cpx:/rnacentral:/uniprot: separados del gen
6LOINCE-1391--solo-loincloinc: y sus seis ejes; fusión con partes y con Wikidata (P4338)
7CIMAE-1404--solo-cimacima: medicamentos y cima:pa: principios activos; fusión VTM = sct:, unión por ATC
8MeSHE-1425--solo-meshmesh:, su árbol como «es un», fusión por P486; «se indexa en MeSH como» desde Orphanet
9DeCSE-1424--solo-decsel español sobre los mesh: (manda la edición de España) y los decs: propios
10HPOE-1426--solo-hpohp: fenotipos, «tiene el fenotipo» enfermedad → síntoma, fusión por P3841
11ClinVarE-1427--solo-clinvar«se asocia con (ClinVar)» gen → enfermedad, con significado y estrellas
12MONDOE-1439--solo-mondocasa los catálogos: fusiones con SNOMED/Orphanet/MeSH/Wikidata por código exacto
13ChEBIE-1440--solo-chebisustancias químicas de referencia; fusión con partes LOINC, «coincide» con Wikidata
14mapa SNOMED→OrphanetE-1452--solo-snomed-orphanetel mapa oficial (refset 784008009): fusión sct:↔orpha: 1↔1
15UMLSE-1441, E-1543--solo-umlsel CUI como dato y como fusión 1↔1 entre fuentes; cinco SAB más de puente
16gene:↔hgnc:E-1486--solo-genes-hgncfusiona el gen-stub de GO con su gen HGNC por símbolo aprobado
17nombres (doble señal)E-1481--solo-nombresfusión por nombre solo con una segunda señal de código; si no, cuestion
18ChEMBLE-1523--solo-chemblfármacos y sus indicaciones: «está indicado para» (aprobada, fase 4) y «está en investigación para» (< 4)
19ChEBI → sustancia peladaE-1540, E-1543--solo-sct-chebida chebi: a la sustancia SNOMED pelada por el CUI de la UMLS y Wikidata
20sustancia ↔ productoE-1536--solo-sustancialleva la química (wd:/mesh:/chembl:) del grupo del producto al de la sustancia, por código
21química que quedaE-1550--solo-sustancia-extrala que E-1536 no movió (ChEBI sin InChI, dos ChEBI), por P592/P683/CAS
22un solo principio activoE-1561--solo-un-pasi el producto tiene un PA, su química es la de la sustancia pelada
23sal y baseE-1557--solo-sal-baseune la sal (donde cuelgan las indicaciones) con su base; si la sal tiene sct: propio, relación «es una sal de»
24MeSH/wd de la baseE-1562--solo-mesh-wddeshace el mesh:/wd: de la base pegado al sct: de su sal
25ChEBI discrepaE-1578--solo-discrepalleva a la sustancia el chebi: de Wikidata que discrepa pero es la misma molécula activa
26profármaco / forma deE-1566--solo-forma-derelación «es una forma de» para el chembl: que sigue en el producto (dabigatrán etexilato)
27literatura (PubTator)E-1538--solo-pubtator860 635 relaciones «(según la literatura)», separadas de lo curado
28derivadaE-1413, E-1442--solo-derivadascompone por regla lo que antes costaba dos o tres saltos: «contiene (principio activo)», «mide», «clasificado en ATC», «gen de», «produce el fenotipo», «se presenta en», «se estudia con», «asociación gen-enfermedad confirmada»
29guarda de nivelesE-1481--solo-niveles**ningún grupo con dos sct:**: retira la fusión más débil y deja «más concreto/general que»
30características y concentradoresE-1480--solo-caracteristicasmarca (en meta) los atributos que son filtro (escala, tiempo…) y los supernodos que no sirven de puente
—precálculoE-1487--solo-precalculolo último: grupo, nivel, cuenta, índices y FTS

La regla sustancia / producto (E-1536 y la cadena E-1540…E-1578). Un principio activo como el ketoprofeno estaba partido en dos grupos: el del producto (sct: VTM «producto con X» + cima:pa:, con la química arrastrada por el ATC) y el de la sustancia (sct: sustancia + chebi:). La química es la sustancia, no el producto: entró en el del producto porque su único puente, el ATC, CIMA lo ancla al SCTID del producto. La cadena de capas la lleva a su grupo, solo por código exacto y **solo cuando la sustancia ya tiene un chebi: al que anclarla; si no hay destino exacto, no se mueve (mejor no unir que unir mal). Cuando dos moléculas no son la misma —una sal con concepto SNOMED propio, un profármaco o éster (dabigatrán etexilato ≠ dabigatrán)— no se funden: se deja una relación con nombre, «es una sal de» (E-1557) o «es una forma de» (E-1566), que el respondedor sigue** con seguir= para alcanzar las indicaciones aprobadas del otro lado (§ 6).


5. Las guardas comunes

Son las reglas que impiden «unir mal», y cada una tiene cómo se comprueba:

  • **Nunca dos sct: en un grupo.** SNOMED es una jerarquía; dos conceptos distintos no son el mismo objeto. La guarda de niveles (capa_niveles, la última de la carga) retira la fusión más débil que los juntaba y, si la jerarquía lo dice, deja «más concreto que» / «más general que». Comprobado: en producción hoy, grupos con dos sct: = 0 (capa_niveles y los tests [tests/test_niveles_nombres_mesa.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_niveles_nombres_mesa.py), test_sal_base_mesa.py).
  • **Dos destinos → cuestion. Si una fuente reclama que un objeto es a la vez dos cosas (un QID con dos SCTID, un ATC de combinación con dos ChEBI…), no se fusiona**: va a cuestion. Hoy hay 24 289 cuestiones abiertas.
  • Ningún nombre cambia. Los nombres de cada fuente entran sin tocar ni un carácter (lo exige la licencia de CIMA, LOINC, HPO…). Las capas de traslado mueven objetos entre grupos, nunca reescriben un apuntador. Lo fijan los tests test_*_mesa.py de cada capa.
  • La guarda de niveles (arriba) y la fusión por nombre con doble señal: un objeto suelto con nombre idéntico a otro se fusiona solo si hay además una segunda señal de código (mismo CUI, mismo CIE-10, mismo OMIM, o el mismo padre ya fusionado); si no, cuestion como «candidato por nombre» (lo revisan Doc o Eduardo).
  • «Mejor no unir que unir mal». Una capa de traslado solo mueve por código exacto y solo cuando hay un destino único; ante la duda, no mueve y, si procede, abre cuestion.
  • Lotes deshacibles. Cada fusión/relación nueva lleva un lote (en regla); a_mesa.py --deshacer-lote <lote> lo retira de un tirón (marca vigente=0, nunca borra) y lo deja dicho en meta['lotes']. Hoy hay manifiestos de E1536-sustancia, E1540-sct-chebi, E1543-sct-chebi, E1557-sal-base, E1561-un-pa, E1562-mesh-wd-a-sustancia, E1578-discrepa, retirada-niveles, nombres-doble-senal, piramide-cie10, rna-go-hgnc, chembl, pubtator. La prueba de que son reversibles: red mesa --publica deja fuera lo de licencia snomed/loinc/aemps/decs.

6. Del dato a la respuesta

Quien pregunta no sabe medicina: lo hace todo con herramientas genéricas de dev/grafo red/consultas.py (clase Mesa), que buscan por nombre, siguen relaciones y cuentan, sobre la mesa abierta de solo lectura:

  • **buscar(texto, tipo?) — los objetos cuyo nombre casa (español o inglés), los más citados primero**; elige por regla (nombre exacto → tipo → más citado), da el id, dice con qué sinónimo casó (coincide) y sus **identidades** (sus códigos en cada vocabulario). Marca dudoso solo cuando de verdad hay que elegir («DMD» es gen y enfermedad: por eso se pasa tipo).
  • **ficha(objetos)** — por lotes: tipo, identidades, datos y relaciones con nombre.
  • **dentro_de / contiene — suben y bajan por la jerarquía «es un»** (en Elaizii no «está en»): familias y tipos.
  • **relaciones(objeto, tipo?, orden_marco?, seguir?) — las relaciones con nombre; avisa cuando corta** (cortado, con por_tipo) y reparte la muestra (E-1553). **seguir= (una o varias relaciones, E-1560/E-1577) trae en la misma lista** las del objeto y las del otro lado de «es una sal de»/«es una forma de», cada fila con su via.
  • **contar(tipo, de?, a?, ademas?) — cuenta en SQL sin listar; ademas** cruza dos filtros en una cuenta («¿qué análisis de orina son cuantitativos?» = contar("sistema", a="Orina", ademas={relacion:"escala", objeto:"Qn"}), 40 ms).
  • **datos, hechos, forma, esquema** — los datos de un objeto, los hechos en que sale, la forma de la red y sus cifras.

El respondedor común ([red/respondedor.py](https://gitlab.com/wordkers/dev/grafo/-/blob/main/red/respondedor.py)): un bucle de pasos JSON cerrado (cada paso pide una herramienta o responde), temperatura 0, hasta 30 pasos y un tope de 60 s por pregunta. La comprobación va en código: la respuesta solo puede citar hechos que vio en esta pregunta; lo que cita de más se le devuelve con el motivo (no se borra en silencio); la lengua la fija y la comprueba el código. La respuesta se arma en dos partes por el código: cumplen (los hechos citados con su frase) y no_consta (lo que falta).

Lo que Syd añade ([syd.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/syd.py)): su alma (FRASES_SYD: quién es, que la jerarquía es «es un», cómo se usan las relaciones con nombre, que la literatura va aparte de lo curado y nunca aconseja), las herramientas de la mesa, y las FORMAS (FORMAS_SYD, E-1506): ante una pregunta conocida («¿qué es X?», «¿qué síntomas da X?», «¿para qué sirve X?»…) el código clasifica y hace el recorrido fijo (y, para las listas, redacta con una plantilla por lengua sin segunda llamada al modelo, E-1522, ~1,5 s); si no encaja, cae al bucle libre. El saber del dominio (qué relación es «síntomas», «código CIE-10», que lo aprobado de la sal es lo aprobado del fármaco) vive aquí, en la forma —su nota—, no en el alma ni en las herramientas.

El sentido de una relación (TX-1670, 09/11/2026): una relación tiene dirección y la forma de la pregunta fija el sentido. relaciones(…, sentido=) acepta «ida» (las que salen del objeto), «vuelta» (las que llegan) o «ambos»; cada paso relaciones de las FORMAS declara el suyo (un test lo exige). «¿Qué síntomas da X?» es «X tiene el fenotipo Y» de ida: el lupus de HPO está fusionado con el de SNOMED y de vuelta salían las enfermedades que lo tienen como fenotipo.

El prospecto desde la sustancia (TX-1663): prospecto(sustancia) baja por el plano a sus presentaciones («contiene (principio activo)» de vuelta, también las de su sal o su forma) y elige UNA por regla, que devuelve en desde_sustancia y Syd dice: con la sección pedida → de esa sustancia sola → no genérico (sin «EFG») → el texto que comparten más → número de registro menor. Metformina → DIANBEN 850 mg (nº 55211). «¿A es un B?» sube además con situar (una marca es del tipo de lo que lleva: Inhixa → enoxaparina → HBPM → heparina).

La voz (TX-1629): SYD_VOZ = «vieja» (por defecto, producción) o «nueva» (primero la respuesta con las palabras de la fuente, el resto de apoyo, sin «el grafo» ni ids). La nueva añade frases al alma (FRASES_VOZ_NUEVA), cambia el texto de las plantillas (PLANTILLAS_VOZ_NUEVA) y quita en código los ids internos que queden (aplicar_voz). Cambia la huella del alma, así que no mezcla la caché. Se enciende con -e SYD_VOZ=nueva en deploy/run.sh (variable SYD_VOZ).

El alma de Syd no lleva recetas ni nombra el motor. El motor es DeepSeek deepseek-v4-flash por wk_llm (proyecto=elaizii, el gasto a llm_gasto); hay un modo opus afinado a mano por la línea de órdenes ([bin/syd-opus](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/bin/syd-opus)), que no se usa desde la web. Doc 🩺 (el médico, [doc.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/doc.py)) no contesta: examina a Syd con el medidor común (exámenes que fabrica la propia mesa, con respuesta conocida) y con preguntas clínicas de rúbrica, y propone mejoras. Ver [docs/doc.md](doc.md) y [docs/syd.md](syd.md).


7. Cómo se trabaja

Formular un encargo para Elaizii. Silicio escribe el encargo (dev/agentes-common/encargos/E-NNNN-…md) con su «hecho» verificable; lo hace Opus en un worktree propio ../elaizii.E-NNNN sobre main. Una capa nueva de la mesa nace con su capa_*, su --solo-*, su lote deshacible y sus tests (sin ellos no está).

Recoger. Se corren los tests: el de juguete y los test_*_mesa.py en el Mac (sin base), y la suite entera en la nave con flock (un pesado a la vez). Antes de nada, mirar el worktree y la rama (clon compartido).

Desplegar (lo hace Silicio, con aviso: es infra compartida). En la nave, con los secretos en el entorno:

export RED_MESA_SQL=…/dev/grafo/red/mesa.sql
set -a; . ~/agents-secrets/snomed.env; . ~/agents-secrets/elaizii.env; set +a
export SNOMED_DB_HOST=127.0.0.1 ELAIZII_DB_HOST=127.0.0.1
nice -n 10 ionice -c3 python3 -m grafo.a_mesa --salida /datos/nvme/elaizii/mesa.sqlite --solo-<capa>   # rehace una capa

Con los tests en verde, se copia la mesa de trabajo a la de producción (/datos/nvme/elaizii/produccion/mesa.sqlite) y se levanta el contenedor con [deploy/run.sh](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/deploy/run.sh) (monta la carpeta de la mesa de producción de solo lectura, /opt/grafo por WK_GRAFO, SYD_MOTOR=ds; API en :8030, MCP en :8032, las dos redes tras Caddy). Las órdenes exactas con que Silicio despliega (05/11/2026, en la nave, como root):

F=$(date +%Y%m%d-%H%M)
git -C /root/Projects/wordkers1/dev/grafo pull --ff-only; git -C /root/Projects/wordkers1/apis/elaizii pull --ff-only
cd /root/Projects/wordkers1/apis/elaizii && S=$(git rev-parse --short HEAD) && nice docker build -q -t wordkers-elaizii:$S .
P=/datos/nvme/elaizii/produccion
nice cp /datos/nvme/elaizii/mesa.sqlite $P/mesa.sqlite.nueva && mv $P/mesa.sqlite $P/mesa.sqlite.$F.anterior && mv $P/mesa.sqlite.nueva $P/mesa.sqlite
IMAGEN=wordkers-elaizii:$S RED=postgres_default GRAFO=/root/Projects/wordkers1/dev/grafo \
  COMMON=/root/Projects/wordkers1/dev/agentes-common bash deploy/run.sh      # el «HTTP 400» del MCP al final es normal
docker network connect despacho_despacho elaizii-api; docker network connect wordkers-net elaizii-api

La imagen lleva por etiqueta el commit (wordkers-elaizii:<commit>), así se sabe qué código sirve. Se guardan tres copias anteriores de producción (mesa.sqlite.<fecha>.anterior); para volver atrás, se mueve una a mesa.sqlite y se relanza run.sh con su imagen. Se comprueba desde fuera:

curl -s https://elaizii-api.wordkers.com/health
curl -s https://elaizii-api.wordkers.com/v1/elaizii/estado
curl -s -X POST https://elaizii-api.wordkers.com/v1/elaizii/preguntar \
  -H 'Content-Type: application/json' -d '{"pregunta":"¿para qué sirve el dabigatrán?"}'

Deshacer un lote (sin reconstruir): python3 -m grafo.a_mesa --salida <mesa> --deshacer-lote <lote> (p. ej. E1557-sal-base). Marca vigente=0 y lo anota en meta['lotes']; nada se borra.


8. Tests y oro

  • De juguete ([tests/_mesa_juguete.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/_mesa_juguete.py), [tests/test_a_mesa.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_a_mesa.py)): fijan el esquema y el mapeo, sin red ni base. El test de juguete monta una mesa pequeña y comprueba que cada capa hace lo que dice.
  • Por capa (tests/test_<fuente>_mesa.py, y los _real.py contra la base): cada capa tiene su familia, que fija sus cifras y sus guardas (dos destinos → cuestión, ningún nombre cambia, nunca dos sct:).
  • Del respondedor y las normas ([tests/test_preguntar.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_preguntar.py)): una fila por cada norma de los respondedores (§ 5.1 de [elaizii-en-la-red.md](elaizii-en-la-red.md)): JSON cerrado, comprobación en código, dos partes, temperatura 0, el que pregunta no escribe…
  • Las preguntas de oro ([tests/test_preguntar_oro.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_preguntar_oro.py)): las que recorren el grafo de punta a punta (diabetes → 73211009; amoxicilina sube a penicilina; fibrosis quística → sus fenotipos; «¿para qué sirve el dabigatrán?»…). Sirven de contrato cuando una capa cambia.
  • Qué es flojo y por qué. El ranking de **buscar en SNOMED fue pobre al principio (ordenaba solo por nombre, sin «apariciones en hechos» que midan relevancia): se afinó por regla en E-1506 (nombre exacto → tipo → más citado), y por eso casos de nombre dispar —la amiloidosis neerlandesa y el síndrome de Fahr— ya se encuentran. Las sales y profármacos (fluoxetina, dabigatrán, DMD**) fueron flojos hasta la cadena E-1557…E-1577, que llevó las indicaciones aprobadas a la sustancia y enseñó al respondedor a seguir «es una sal de» / «es una forma de»; hoy el dabigatrán resuelve (§ 1). Donde la fuente no trae el dato (OMIM, nombres de la CIE-10), Syd dice «el grafo no lo dice», y eso es lo correcto.

9. Las cifras de hoy

Medidas sobre la copia de producción (/datos/nvme/elaizii/produccion/mesa.sqlite, mode=ro) el 05/11/2026 11:43 CET. La consulta, al pie.

QuéCifra
Objetos (total / vigentes)2 165 990 / 2 013 840
Apuntadores (nombres)5 340 637
Hechos5 903 781
Relaciones (todas vigentes)5 903 781
Fusiones (total / vigentes)162 726 / 159 925
Grupos de fusión (grupo_info)99 991
Cuestiones abiertas24 289
Grupos de producto (un sct: de tipo producto)40 790
chembl: que siguen en un grupo de producto175
wd: que siguen en un grupo de producto173
chembl: en la mesa (vigentes)10 073
Grupos con sct: y alguna «está indicado para» (aprobada)1 248
Relaciones «está indicado para» / «está en investigación para»10 181 / 64 246
Relaciones «(según la literatura)» (PubTator)860 635

Objetos vigentes por tipo (los mayores): valor 1 069 080 · otro 158 669 · hallazgo 132 223 · análisis 112 405 · procedimiento 60 425 · gen 45 289 · estructura corporal 43 681 · producto 40 790 · organismo 34 700 · enfermedad (MONDO) 32 134 · descriptor MeSH 31 110 · sustancia 29 557 · medicamento 25 511 · proceso biológico 23 974 · fenotipo (HPO) 19 894 · objeto físico 14 143 · calificador 12 795 · código CIE-10 12 207.

Hechos por fuente (18 fuentes): snomed 1 558 358 · pubtator 860 635 · umls 692 801 · loinc 640 488 · hpo 638 148 · gene_ontology 543 134 · wikidata 241 692 · cima 217 110 · hgnc 163 345 · orphanet 81 927 · chembl 78 558 · mondo 56 560 · chebi 45 048 · mesh 43 637 · elaizii 16 894 · clinvar 12 577 · complexportal 8 773 · decs 4 096.

Fusiones vigentes por lote (las mayores): HGNC P354 42 730 · MeSH P486 30 968 · MONDO P5270 (Wikidata) 11 054 · UMLS CUI 10 087 · Orphanet P1550 8 802 · MONDO exactMatch SNOMED 8 775 · MONDO exactMatch Orphanet 8 354 · mapa oficial SNOMED→Orphanet 6 235 · nombres-doble-senal 6 046 · LOINC parte ≡ SNOMED 5 466 · HPO P3841 4 690 · MONDO exactMatch MeSH 3 168 · UMLS confirma 2 533 · VTM de CIMA 2 262 · ChEBI ≡ parte LOINC 1 893 · E1536-sustancia 1 650 · Wikidata P5806 1 265 · E1557-sal-base 1 083 · rna-go-hgnc 668 · E1561-un-pa 654 · E1540-sct-chebi 390 · E1543-sct-chebi 343.

La consulta (SQLite, solo lectura; rep(objeto) sigue las fusiones por la tabla grupo):

SELECT count(*) FROM objeto WHERE vigente=1;                         -- objetos vigentes
SELECT count(*) FROM relacion WHERE vigente=1;                       -- relaciones
SELECT count(*) FROM fusion   WHERE vigente=1;                       -- fusiones vigentes
SELECT count(*) FROM grupo_info;                                     -- grupos
SELECT count(*) FROM cuestion  WHERE abierta=1;                      -- cuestiones abiertas
SELECT regla, count(*) FROM fusion WHERE vigente=1 GROUP BY regla;   -- fusiones por lote
SELECT fuente, count(*) FROM hecho GROUP BY fuente;                  -- hechos por fuente
-- grupos de producto, y chembl:/wd: que siguen en ellos:
CREATE TEMP TABLE repmap AS SELECT o.id objeto, COALESCE(g.representante,o.id) rep
  FROM objeto o LEFT JOIN grupo g ON g.objeto=o.id WHERE o.vigente=1;
CREATE TEMP TABLE prodrep AS SELECT DISTINCT r.rep FROM repmap r JOIN objeto o ON o.id=r.objeto
  WHERE o.tipo='producto' AND o.id LIKE 'sct:%';
SELECT count(*) FROM repmap r WHERE r.objeto LIKE 'chembl:%' AND r.rep IN (SELECT rep FROM prodrep);
-- grupos con sct: y alguna aprobada:
SELECT count(DISTINCT dr.rep) FROM relacion rel JOIN repmap dr ON dr.objeto=rel.de
  WHERE rel.vigente=1 AND rel.tipo_objeto='tipo:chembl:indicado'
  AND dr.rep IN (SELECT DISTINCT rep FROM repmap WHERE objeto LIKE 'sct:%');

Ojo a la frescura: la meta «cuando» de la mesa de producción dice 2026-10-28T21:29:27 (la última construcción entera), pero la mesa se ha ido poniendo al día capa a capa (--solo-*), y la última (capa_profarmaco, E-1566) corrió el 05/11/2026 10:17 (las marcas *_cuando de meta lo dicen). Las cifras de arriba son del contenido vivo, no de esa meta.


10. Lo que queda y lo que se decidió no hacer

  • Doc entrenando solo (TX-1369, hecha el 29/10/2026 23:19): los programas de Cronos de Doc (dos tandas al día + doc-semana) están activos en la nave (comprobado en gestion.programas el 09/11/2026 10:50). elaizii-en-la-red.md § 6 paso 5.
  • **Modo opus de Syd**: implementado ([bin/syd-opus](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/bin/syd-opus)) pero no cableado desde doc-tanda; cuando lo esté, se compara la nota de DeepSeek frente a Opus por tipo (modo independiente).
  • Fuentes por licencia (elaizii-en-la-red.md § 6.1–6.3): OMIM queda fuera (su acuerdo prohíbe distribuir y hacer obras derivadas; E-1438/§ 6.2). De la ATC de la OMS no se pide nada (ni el fichero de pago ni la versión en español): los códigos entran por CIMA; los nombres de la OMS solo si salen de CIMA con permiso. La UMLS se pidió (cuenta UTS a nombre de Eduardo, TX-1441); ya está cargada (2026AA). DeCS exigió firmar un acuerdo (OPS/BIREME); cargada, solo en la mesa de Elaizii, no en la estantería común. La CIE-10-ES (los títulos de los códigos) cuelga de un aviso genérico del Ministerio y de una obra base de NCHS: antes de cargar los nombres conviene preguntar al Ministerio, como con CIMA.
  • La identidad con el resto de la red por P5806 es estrecha (1 449 ítems en Wikidata); por eso la cobertura se amplió con MONDO, la UMLS y los puentes de Wikidata (E-1438/E-1439/E-1441). La CIE-10 de SNOMED es relación, no fusión (un código no es el mismo objeto que un concepto).

11. Índice de encargos (trabajo TX-1362)

Los encargos de fondo del trabajo, por los que la red es como es (los informes están en dev/agentes-common/encargos/E-NNNN-informe.md). Hay además encargos intermedios de despliegue y arreglo con el mismo número de TX; esta tabla recoge los de sustancia citados por [elaizii-en-la-red.md](elaizii-en-la-red.md).

EncargoFechaQué hizoInforme
E-13632026-10-28El respondedor común pasa a la librería (red/respondedor.py), sin saber de ninguna redE-1363-informe.md
E-13642026-10-28El medidor de la red: la propia red fabrica exámenes con respuesta conocida y se puntúa sin juezE-1364-informe.md
E-13652026-10-28La mesa de Elaizii: a_mesa.py vuelca SNOMED al esquema comúnE-1365-informe.md
E-13672026-10-28Ruta de preguntas para cualquier red, con MCP y consultas enlazablesE-1367-informe.md
E-13682026-10-29Syd deja su bucle: pasa a ser configuración Red de Elaizii sobre el respondedor comúnE-1368-informe.md
E-13772026-10-29capa_cie10: la CIE-10 por los mapas de SNOMED, como relación no fusiónE-1377-informe.md
E-13782026-10-29Wikidata médica, unida a SNOMED por P5806E-1378-informe.md
E-13822026-10-29Orphanet (raras) y capa_orphanet, por código exactoE-1382-informe.md
E-13892026-10-29Genes: HGNC y Gene Ontology (capa_genes)E-1389-informe.md
E-13912026-10-29LOINC a Elaizii (capa_loinc)E-1391-informe.md
E-14042026-10-29Medicamentos de CIMA (AEMPS), unidos por el código ATCE-1404-informe.md
E-14132026-10-29La capa DERIVADA: conectar por regla explícita lo que ayuda a SydE-1413-informe.md
E-14232026-10-29avisos.py: un texto fijo con los avisos de TODAS las fuentes de la mesaE-1423-informe.md
E-14242026-10-29capa_decs: DeCS (español) sobre MeSH por el UI exactoE-1424-informe.md
E-14252026-10-29MeSH (NLM) y capa_mesh, por códigoE-1425-informe.md
E-14262026-10-29HPO (fenotipos) y capa_hpo: enfermedad → sus síntomas en españolE-1426-informe.md
E-14272026-10-29ClinVar (NCBI) y capa_clinvar: gen → enfermedadE-1427-informe.md
E-14382026-10-30Wikidata ampliado: puentes por código; fusiones 10 591 → 98 073E-1438-informe.md
E-14392026-10-30MONDO: puente entre los catálogos de enfermedadE-1439-informe.md
E-14402026-10-30ChEBI: la sustancia química, puente del análisis a la sustanciaE-1440-informe.md
E-14412026-10-30UMLS: el CUI como puente por código (capa_umls)E-1441-informe.md
E-14422026-10-30Reglas nuevas de la capa derivada (gen → síntoma, etc.)E-1442-informe.md
E-14522026-10-30capa_snomed_orphanet: el mapa oficial SNOMED CT → OrphanetE-1452-informe.md
E-14532026-10-30Narrar bien tres fallos de producción, por regla en consultas.pyE-1453-informe.md
E-14782026-10-30Red más tupida: familias de genes HGNC y estado de OrphanetE-1478-informe.md
E-14802026-10-30Características y concentradores (capa_caracteristicas)E-1480-informe.md
E-14812026-10-31Lotes deshacibles, guarda de niveles y fusión por nombre con doble señalE-1481-informe.md
E-14822026-10-30Pirámide de la CIE-10 por código y mapa condicionalE-1482-informe.md
E-14862026-10-31El cuelgue de «orina cuantitativa», tope por pregunta, gene:↔hgnc:E-1486-informe.md
E-14872026-11-01La mesa: índices y tablas precalculadas (grupo, nivel, cuenta)E-1487-informe.md
E-15062026-11-02Syd: clasificar en una FORMA y recorrido en código; «buscar» por reglaE-1506-informe.md
E-15212026-11-03Gene Ontology: separar ARN y complejos de los genesE-1521-informe.md
E-15222026-11-03Plantillas: el código redacta las listas sin el modelo (~1,5 s)E-1522-informe.md
E-15232026-11-03ChEMBL: enfermedad ↔ tratamiento, con la fase de ensayoE-1523-informe.md
E-15362026-11-03Sustancia y producto: cada identidad química a su grupoE-1536-informe.md
E-15382026-11-03PubTator3 (literatura), agregado y separado de lo curadoE-1538-informe.md
E-15402026-11-03chebi: a las sustancias SNOMED peladas, vía UMLSE-1540-informe.md
E-15432026-11-04Las 781 que quedaban: amplía UMLS y puentea por WikidataE-1543-informe.md
E-15502026-11-04La química que se queda en el producto (capa_sustancia_producto_extra)E-1550-informe.md
E-15532026-11-04relaciones cortaba en 40 sin avisar: reparte la muestraE-1553-informe.md
E-15572026-11-04Las indicaciones cuelgan de la sal: une sal y baseE-1557-informe.md
E-15602026-11-04relaciones(seguir=) para «es una sal de»E-1560-informe.md
E-15612026-11-04El producto de un solo PA lleva su química a la sustancia (capa_sustancia_un_pa)E-1561-informe.md
E-15622026-11-04capa_mesh_wd_sustancia: el mesh:/wd: de la base vuelve a la sustanciaE-1562-informe.md
E-15662026-11-05capa_profarmaco: «es una forma de» para los chembl: del productoE-1566-informe.md
E-15772026-11-05Juntar los caminos en el dato (seguir= lista): «está aprobado para…»E-1577-informe.md
E-15782026-11-05capa_chebi_discrepa: el chebi: de Wikidata discrepa pero es la misma moléculaE-1578-informe.md

Firmado Karb and Sil · CC BY 4.0.

12. Fuentes

De dónde sale lo que dice esta página. Los informes de los encargos viven en dev/agentes-common/encargos/, que Ariadna no publica: se enlazan en GitLab. Enlazado por programa el 05/11/2026 (pedido de Eduardo).

Documentos de este repo: doc.md · elaizii-en-la-red.md · fuentes-er.md · mcp.md · modelo.md · operaciones.md · syd.md

Informes de encargos: E-1361 · E-1363 · E-1364 · E-1365 · E-1367 · E-1368 · E-1377 · E-1378 · E-1382 · E-1389 · E-1391 · E-1404 · E-1413 · E-1423 · E-1424 · E-1425 · E-1426 · E-1427 · E-1438 · E-1439 · E-1440 · E-1441 · E-1442 · E-1452 · E-1453 · E-1478 · E-1480 · E-1481 · E-1482 · E-1486 · E-1487 · E-1506 · E-1521 · E-1522 · E-1523 · E-1536 · E-1538 · E-1540 · E-1543 · E-1550 · E-1553 · E-1557 · E-1560 · E-1561 · E-1562 · E-1566 · E-1577 · E-1578

Código: [avisos.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/avisos.py) · [bin/syd-opus](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/bin/syd-opus) · [deploy/run.sh](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/deploy/run.sh) · [doc.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/doc.py) · [grafo/a_mesa.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/grafo/a_mesa.py) · [red/consultas.py](https://gitlab.com/wordkers/dev/grafo/-/blob/main/red/consultas.py) · [red/respondedor.py](https://gitlab.com/wordkers/dev/grafo/-/blob/main/red/respondedor.py) · [syd.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/syd.py) · [tests/_mesa_juguete.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/_mesa_juguete.py) · [tests/test_a_mesa.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_a_mesa.py) · [tests/test_niveles_nombres_mesa.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_niveles_nombres_mesa.py) · [tests/test_preguntar.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_preguntar.py) · [tests/test_preguntar_oro.py](https://gitlab.com/wordkers/apis/elaizii/-/blob/main/tests/test_preguntar_oro.py)

En esta página