Parte V · En la práctica
Una historia clínica
El spa y el taxi eran negocios transaccionales: eventos que ocurren, se cobran y se olvidan. La medicina es lo contrario. Aquí lo valioso no es la cita, sino el conocimiento denso que nace dentro de ella —y que tiene que sobrevivir décadas.
Son las 09:40 de un martes en cardiología. Llega Gonzales, la misma que meses atrás entró por urgencias con una fibrilación. Hoy viene a un control de rutina.
No hay drama. Se sienta y cuenta que duerme mal, que a veces siente el corazón «a destiempo».
La doctora le toma la presión y repasa su última analítica. La hipertensión sigue ahí, algo peor. Ajusta la dosis de un fármaco. Anota una alergia que la paciente no conocía. Agenda otro control en treinta días.
Quince minutos. Gonzales sale por la puerta y la cita termina.
Pero casi nada de lo que importa termina con ella. El diagnóstico seguirá vigente un año. La receta habrá que revisarla cada mes. La alergia recién descubierta tendrá que gritar cada vez que alguien intente recetarle ese fármaco.
Esos quince minutos dejaron un sedimento. Un médico distinto, en un hospital distinto, dentro de cinco años, tendrá que poder leerlo sin dudas. Ese sedimento es el examen de este capítulo.
Los negocios de esta parte del libro giraban alrededor de la transacción. Una sesión de spa empieza, termina, se cobra. Un viaje en taxi ocurre, se paga, se archiva. Modelarlos fue repetir una fórmula cambiando las palabras.
La medicina no concede esa comodidad. Una consulta también es un evento, pero a nadie le importa cuánto duró. Importa lo que se produjo dentro: un diagnóstico, una receta, una alerta de alergia, un control programado.
Y ese contenido tiene que vivir mucho más que la cita que lo produjo.
Por eso este capítulo cambia de foco. Aquí no exhibo una solución terminada, sino cómo se modela un dominio nuevo desde cero.
La medicina sirve para eso porque nadie llega con el esquema resuelto. Hay que sacarlo a la luz decisión por decisión, viendo dónde acierta la intuición y dónde el modelo nos corrige a tiempo.
La pregunta que gobierna el capítulo
¿Aguanta el modelo un dominio para el que no fue diseñado, sin inventar maquinaria nueva? La apuesta es que sí. Una consulta médica completa cae sobre los mismos siete ejes y el mismo lexicon que ya conoces, con toda su incertidumbre y su vigencia en el tiempo. Donde haya fricción, la mostraré tal cual.
Cómo se elicita un dominio que no conoces
Modelar un dominio nuevo no empieza escribiendo tripletas. Empieza con tres preguntas al negocio, en este orden, antes de tocar el teclado. Sirven igual para una clínica que para una aseguradora o una fábrica.
🗂️
¿Cuál es el evento ancla?
El acontecimiento alrededor del cual orbita todo lo demás. En el spa era la venta; aquí es la consulta. De él colgarán las demás piezas.
🧩
¿Qué nace dentro del evento?
Los «objetos de información» que la consulta produce: síntoma, medición, diagnóstico, prescripción, control. Cada uno con vida propia.
🔮
¿Sobre qué se preguntará mañana?
La prueba decisiva de qué merece volverse entidad. Si alguien va a interrogar un dato en el futuro, ese dato necesita identidad propia.
La tercera es la más sutil y queda para el final del capítulo. Por ahora basta la primera: el evento ancla. En medicina, ese evento es la consulta.
La consulta como carpeta maestra
Igual que en el taxi un viaje abrazaba a todos sus pasos menudos, la consulta
médica actúa como una gran carpeta articuladora. Una revisión típica produce cinco piezas
internas, y conviene nombrarlas como las nombraría el propio médico:
1 · El síntoma. Lo que dice el paciente, en sus palabras: «duermo mal y siento el
corazón a destiempo». Subjetivo, fechado, con una intensidad que mañana querremos
comparar.
2 · La medición. Los números crudos que toma la doctora: presión en 148/95. Objetivos,
con unidad y momento.
3 · El diagnóstico. La conclusión clínica: hipertensión de grado 2. Una inferencia,
no un hecho duro, y con fecha de caducidad.
4 · La prescripción. La conducta indicada: subir el antihipertensivo a 20 mg,
una vez al día. Tiene un porqué, una finalidad y un control de seguridad.
5 · El control. El plan a futuro: nueva cita en treinta días. No es algo que pasó,
sino algo previsto, y el sistema debe saber distinguirlo de lo real.
En el modelo, estas cinco piezas no son campos de texto de la consulta.
Son cinco situaciones reificadas independientes que cuelgan del evento ancla con el viejo y
confiable cable parte_de. La consulta reúne; cada pieza vive su propia vida.
(consulta_8842) ∈ O
instancia_de : consulta_cardiologia # K · qué clase de evento es
agente : dra_navarro # Q · quién atiende
paciente : maria_g # Q · a quién se atiende
lugar_de : consultorio_card_2 # L · dónde ocurre
inicio : 2026-06-09T09:40-05:00 # T · cuándo
motivo : control_hipertension # K · por qué viene
(sintoma_8842 ∈ O, parte_de, consulta_8842)
(medicion_8842 ∈ O, parte_de, consulta_8842)
(diag_hta_8842 ∈ O, parte_de, consulta_8842)
(prescrip_8842 ∈ O, parte_de, consulta_8842)
(control_8842 ∈ O, parte_de, consulta_8842)
La arquitectura no se inmuta: una entidad grande que contiene un racimo de piezas menores, igual que la venta del spa contenía sus líneas.
La consulta cumple de sobra las condiciones para volverse situación en O.
Agrupa varias partes, está fechada, tiene participantes con roles y, sobre todo, otras cosas
le harán referencia.
Lo interesante de la medicina no es el contenedor. Es el interior de cada pieza.
maria_g y la doctora en
Q, el consultorio en L, el momento en T). Abajo,
las cinco sub-situaciones que nacen dentro de ella y cuelgan con parte_de.
La consulta no «guarda» el diagnóstico como un campo: lo articula como una
entidad vecina con vida propia.El bache: cuando el eje O se queda corto
Aquí apareció la primera fricción real al programar este dominio. Vale la pena contarla, porque enseña más que cualquier acierto.
La intuición dice: «el tema de esta medición es la presión arterial». Y con la receta: «el tema de esta prescripción es el fármaco». Parece obvio.
Pero detente. «Presión arterial» y «el antihipertensivo» no son cosas físicas con identidad propia. No puedes guardar «la presión arterial universal» en un cajón. Es una magnitud, una categoría teórica.
La caja de pastillas que Gonzales compra en la farmacia sí es un objeto del eje
O: tiene lote, vencimiento, ubicación. El concepto científico del fármaco, en
cambio, es una clase, un habitante del eje K.
El instinto mezcla lo físico con lo conceptual sin darse cuenta.
El catálogo del modelo no se deja engañar. El cable tema solo admite conectar
O con O. Si intento apuntar de una medición (en O)
hacia la magnitud presión (en K), el sistema aborta y me regaña por mezclar
peras con manzanas.
El modelo se niega a aceptar el disparate
Conectar una situación de O con una clase de K
usando un cable que exige O→O lanza un SignatureError. No es un
estorbo: es la frontera que impide que un dato mal puesto entre al grafo. El error no
estaba en el modelo, sino en mi cabeza, que confunde el objeto concreto con la idea
abstracta.
La salida no es forzar el cable genérico. Es declarar cables de dominio: roles
propios de la medicina, hechos para apuntar hacia el eje K. Cada industria muy
técnica reclama un puñado de cables exclusivos para sus conceptos abstractos.
# Mal · forzar el cable genérico "tema" hacia una clase → SignatureError
# Bien · declarar cables de dominio cuya firma apunta a K
u.assert_fact(medicion_8842, "medida_evaluada", presion_arterial) # O → K
u.assert_fact(prescrip_8842, "medicamento_prescrito", antihipertensivo) # O → K
Dos lecciones de la fricción
- El catálogo universal cubre casi todo, pero no todo. Los roles base sirven para la inmensa mayoría de los hechos; cada dominio altamente técnico (medicina, química, derecho) pedirá unos pocos cables propios para sus abstracciones. Eso es esperado, no un fallo.
- El error fue del modelador, no del modelo. La firma estricta no es burocracia:
es la que distingue «la caja de pastillas» (objeto,
O) del «fármaco como concepto» (clase,K). Sin esa distinción, una IA no podría razonar sobre interacciones farmacológicas.
Diseccionar un diagnóstico: duda, evidencia y tiempo
Un diagnóstico es la pieza más rica de toda la consulta, porque cruza a la vez tres dimensiones que un sistema de juguete suele aplastar en un solo campo de texto. El modelo las resuelve por separado, sin esfuerzo.
1 · El nivel de duda
Un diagnóstico casi nunca es una verdad tallada en piedra. Es lo que la doctora cree en ese instante, con la evidencia que tiene.
Para no perder esa duda clínica, marcamos la situación con su grado de certeza: puede ser sospechado, confirmado o descartado.
La diferencia entre «sospecho una arritmia» y «confirmo una arritmia» no es un matiz de prosa. Cambia qué se puede recetar y qué hay que vigilar.
(diag_hta_8842, modalidad, epistemica) # K · pertenece al saber, no al deseo
(diag_hta_8842, estatus_factual, confirmado) # K · sospechado | confirmado | descartado
Es la misma distinción que en el spa separaba la venta real de la simple intención de compra. Que un dato pueda ser «todavía no seguro» sin ser falso hace falta en cualquier dominio serio.
2 · La evidencia
Un diagnóstico no nace de la nada. Nace de los números. Si la doctora escribe «hipertensión», es porque vio la medición de presión.
Esa conexión no se guarda en un comentario. Se ata con un cable. Como vimos al hablar del «por qué», no hay un eje para eso: el porqué se reparte en cables distintos, y aquí toca el que apunta a la razón de la conclusión.
(diag_hta_8842, motivado_por, medicion_8842) # M · la medición es la evidencia
Con ese cable, la medición deja de ser un número suelto y pasa a ser la evidencia del diagnóstico.
Si un auditor médico revisa el expediente y pregunta «¿en qué se basó esto?», nadie tiene que interpretar prosa. Se lee siguiendo el cable. La justificación viaja con el dato.
3 · El viaje en el tiempo
Aquí se separa el software hospitalario de verdad del de juguete. Los diagnósticos caducan y cambian.
Tras el episodio agudo, en marzo, a Gonzales le asignaron hipertensión de grado 1. En esta consulta de junio la doctora confirma que empeoró: ahora es grado 2.
Si el sistema escribiera el diagnóstico nuevo encima del viejo, borraría la historia de la paciente. Eso no es solo mala medicina. Deja el caso sin manera de reconstruirse.
La regla de vigencia entra a salvarnos. No se sobrescribe nada: se guardan ambos diagnósticos, cada uno con su rango de validez, y se los conecta para que la cronología sea legible.
# El diagnóstico viejo: válido desde marzo, cerrado cuando se emite el nuevo
u.assert_fact(diag_marzo, "diagnostico_asignado", hta_grado_1,
valid_from="2026-03-12", valid_to="2026-06-09")
# El diagnóstico nuevo: vigente desde hoy, sin fin (sigue activo)
u.assert_fact(diag_hta_8842, "diagnostico_asignado", hta_grado_2,
valid_from="2026-06-09")
# Y se enlazan, para que la cronología no quede a interpretación
u.assert_fact(diag_hta_8842, "rectifica", diag_marzo) # M · este corrige a aquel
El premio viene de fábrica. Si mañana hay una demanda y el juez pregunta «¿qué sabía el hospital sobre este paciente en abril?», la base no devuelve el estado de hoy.
Devuelve la verdad clínica que regía en abril, grado 1, ignorando todo lo que se supo después. Basta una consulta con un filtro de fecha.
rectifica conecta ambos. Una
consulta fechada en abril (la línea vertical) atraviesa solo la barra del grado 1 y
devuelve esa verdad —no la de hoy—. La reconstrucción del pasado es una proyección, no un
archivo de respaldo.La prescripción y la tormenta de los porqués
Cuando la doctora ajusta el fármaco se activan varias fuerzas causales a la vez. Una receta no es un dato suelto. Es una decisión con un motivo, un objetivo y un control de seguridad, y el modelo guarda cada uno en su propio cable.
pres = ingest_situation(u, lex, "prescribir",
roles={
"agente": dra_navarro,
"paciente": maria_g,
"medicamento_prescrito": antihipertensivo, # O → K
"dosis": "20 mg",
"frecuencia": cada_manana,
},
sit_id="prescrip_8842",
)
u.assert_fact(pres, "motivado_por", diag_hta_8842) # ← por qué se receta
u.assert_fact(pres, "con_finalidad", meta_presion_objetivo) # ← para qué se receta
u.assert_fact(pres, "verificado_contra", regla_renal_alerta) # ← qué ley clínica la valida
Tres respuestas a tres preguntas distintas. La doctora no receta por gusto: lo hace motivada por el diagnóstico, con la finalidad de bajar la presión a una meta, y verificando que el ajuste no dañe unos riñones que ya vienen tocados.
Tres cables, tres porqués, ningún campo de texto ambiguo.
Contraindicación como objeto, no como código
La regla de seguridad («no combinar este fármaco con tal condición
renal») no está escondida en el código de la aplicación. Es una situación más en el
eje O, con su clase, su fármaco implicado, su condición disparadora y su
orden. Como cualquier norma, tiene autor y fecha de vigencia, y vive en el grafo a la
vista de todos.
(regla_renal_alerta) ∈ O
instancia_de : contraindicacion_clinica # K · qué clase de norma es
medicamento_implicado: antihipertensivo # K · sobre qué fármaco recae
condicion_gatillo : funcion_renal_reducida # K · qué condición la dispara
orden_oficial : revisar_antes_de_recetar # K · qué exige
vigente_desde : 2025-01-01 # T · desde cuándo rige
emitida_por : guia_cardiologia_nacional # Q · qué autoridad la dicta
Con la regla dentro del grafo, la base se vuelve lista sin volverse rígida.
Cuando la doctora pulsa «recetar», un motor externo (o una IA) recorre el grafo, encuentra la norma, comprueba la función renal del paciente y levanta una alerta antes de que ocurra el daño.
El grafo guarda la verdad. La lógica que la aplica vive afuera. Esa separación es deliberada, igual que en el spa: el modelo no ejecuta la regla de negocio, la deja legible para que quien la ejecute no se equivoque.
El control futuro: cuando el dato aún no es real
La quinta pieza, el control a treinta días, parece trivial y esconde algo importante. Todavía no ocurrió: es un plan. Si el sistema lo guardara como hecho consumado, ensuciaría cualquier informe. Contaríamos como «atendida» una cita que no existe.
El modelo lo marca como previsto, no como real, con la misma maquinaria que usamos para el diagnóstico sospechado.
(control_8842) ∈ O
instancia_de : consulta_cardiologia
paciente : maria_g
agente : dra_navarro
inicio_previsto : 2026-07-09 # T · la fecha agendada
estatus_factual : previsto # K · ¡aún no es real!
motivado_por : diag_hta_8842 # M · se controla esta hipertensión
Gracias a ese rótulo, el sistema responde sin tropezar a «¿qué citas tiene Gonzales agendadas?», donde el control aparece, y a «¿cuántos pacientes atendió la doctora en junio?», donde no aparece porque aún no sucedió. Lo previsto y lo real conviven sin confundirse.
La historia clínica como serie temporal
Hasta aquí hemos diseccionado una consulta. Pero Gonzales no es una consulta. Es una paciente con años de roce con el sistema sanitario.
La misma que entró por urgencias con una fibrilación. La que en marzo recibió su primer diagnóstico de hipertensión. La que hoy vuelve al control de cardiología. La que dentro de unas páginas pasará unos días ingresada.
Su identidad es una sola, cosida con el mismo maria_g que ya recorre la tienda
y la clínica. Lo que cambia es el rosario de situaciones que cuelgan de ella con los años.
Eso es una historia clínica: no un documento, sino una fila de episodios en el tiempo.
En el modelo, la historia no es una tabla con una fila por visita. Es el conjunto de todas
las situaciones cuyo paciente es maria_g, puestas en orden por el
eje T y filtradas por la vigencia que cada hecho declara.
Cada episodio (una urgencia, una analítica, una consulta, un ingreso) es una situación más
en O que apunta al mismo paciente. Recuperar «la historia de Gonzales» es barrer
el grafo por ese nodo y leer la cinta.
# Cada episodio es una situación que apunta al MISMO paciente, situada en T
(urgencias_2403, paciente, maria_g) # T: 2026-02-14 · la fibrilación
(analitica_2511, paciente, maria_g) # T: 2026-03-05 · sangre y lípidos
(consulta_3019, paciente, maria_g) # T: 2026-03-12 · 1er dx de HTA grado 1
(consulta_8842, paciente, maria_g) # T: 2026-06-09 · el control de hoy
(ingreso_9120, paciente, maria_g) # T: 2026-06-14 · el ingreso (más abajo)
# La historia = proyección por paciente, ordenada por T, con la vigencia de cada hecho
historia = u.timeline(maria_g, valid_at="2026-06-19")
Esa cinta lleva dos tiempos a la vez. Registra cuándo ocurrió cada episodio, en el
eje T, y también desde cuándo y hasta cuándo se tuvo por cierta cada
afirmación clínica.
Es la misma vigencia (D6) que salvó al diagnóstico de pisarse a sí mismo, ahora aplicada a la historia entera.
Por eso caben dos preguntas distintas. «¿Qué le pasó a Gonzales en abril?» corta por el tiempo del hecho. «¿Qué creía saber el hospital sobre Gonzales en abril?» corta por el tiempo del registro.
Un expediente de juguete confunde las dos. El grafo las separa de fábrica.
maria_g, en Q) es
una sola; cada urgencia, analítica, consulta o ingreso es una situación independiente en
O que la referencia y se ordena por su eje T. La bitemporalidad
(D6) permite leer la cinta «como ocurrió» o «como se creía» en cualquier fecha pasada.La hospitalización: una situación-marco que contiene eventos
El control de hoy detectó algo que no tranquiliza: la presión no cede y la paciente tiene mareos. La doctora decide ingresarla unos días para vigilancia.
Aparece entonces una estructura que la consulta ya insinuaba y que el ingreso lleva al extremo: una situación-marco que contiene a otras.
Si la consulta era una carpeta de cinco piezas, la hospitalización es una carpeta de carpetas. Una caja con paredes de tiempo, dentro de la cual ocurren decenas de eventos menudos: admisión, asignación de cama, signos vitales cada turno, rondas médicas, cada dosis, la evolución diaria. Hasta que se cierra con el alta.
El instinto equivocado sería crear una tabla hospitalizaciones con columnas
para «cama», «fecha de alta» y un campo de texto «notas». El modelo no necesita nada de
eso.
El ingreso es una situación más en O, con su propio identificador, y todo lo
que ocurre dentro le cuelga con el cable de siempre: parte_de. La
hospitalización no es un registro. Es un contenedor.
(ingreso_9120) ∈ O
instancia_de : hospitalizacion # K · qué clase de marco es
paciente : maria_g # Q · a quién se ingresa
agente : dra_navarro # Q · quién lo indica
servicio : cardiologia # K · bajo qué servicio
cama : cama_4b_307 # O · la cama asignada (objeto físico)
inicio : 2026-06-14T11:20-05:00 # T · cuándo se admite
estatus : en_curso # K · admitido | en_curso | de_alta
# Todo lo que ocurre adentro cuelga del marco con parte_de
(admision_9120, ∈ O, parte_de, ingreso_9120) # T: 14 jun 11:20
(signos_9120_t1, ∈ O, parte_de, ingreso_9120) # T: 14 jun, ronda mañana
(ronda_9120_d1, ∈ O, parte_de, ingreso_9120) # T: 14 jun, visita médica
(adm_farmaco_9120, ∈ O, parte_de, ingreso_9120) # T: 14 jun, dosis administrada
(evolucion_9120_d2,∈ O, parte_de, ingreso_9120) # T: 15 jun, nota de evolución
(alta_9120, ∈ O, parte_de, ingreso_9120) # T: 17 jun, cierre del marco
Fíjate en la cama. cama_4b_307 es un objeto físico en O, no una
etiqueta: tiene ubicación, ocupación, mantenimiento.
Que el ingreso la señale por L/O en vez de copiarla como texto es
lo que permite responder «¿qué camas están libres en cardiología ahora mismo?» sin inventar
otra tabla.
El servicio (cardiologia) es otra cosa: una clase en K. Nadie
pregunta por su identidad; se usa como categoría.
El premio de modelar el ingreso como marco es que cada evento interior conserva su contexto sin repetirlo. La dosis del 14 de junio no arrastra «paciente Gonzales, servicio cardiología, cama 307».
Todo eso se hereda subiendo por parte_de hasta el marco. La trazabilidad es
estructural, no copiada.
T (la admisión abre la caja, el alta la cierra);
dentro ocurren, en orden, la asignación de cama, los signos vitales, las rondas, la
medicación administrada y las notas de evolución. Todos cuelgan del marco con
parte_de y heredan su contexto sin repetirlo. Un contenedor, no un registro.El enlace con la farmacia interna: prescripción, dispensación, administración
Hay un eslabón que el software hospitalario de juguete casi siempre rompe: lo que la doctora receta no es lo que el paciente recibe.
Entre la receta y el cuerpo de Gonzales hay una cadena de custodia que cruza el módulo clínico con el de farmacia, igual que en un ERP el de ventas conversa con el de inventario.
Son tres situaciones encadenadas, cada una con su autor y su momento: la prescripción, donde la doctora ordena; la dispensación, donde la farmacia entrega un lote concreto; y la administración, donde la enfermería se lo aplica al paciente.
El detalle que lo cambia todo es el lote. La farmacia no entrega «el
antihipertensivo», que es un concepto en K. Entrega una caja física con su
vencimiento y su rastro, igual que en minería un saco de mineral arrastra su origen.
Si mañana retiran ese lote por un defecto de fabricación, el grafo tiene que responder en segundos: «¿a qué pacientes se les administró algo de este lote?».
Esa pregunta solo tiene respuesta si el lote es un objeto en O y no un texto en
un comentario.
# El lote es un OBJETO físico en O, con su vencimiento y su clase de fármaco
(lote_av2207) ∈ O
instancia_de : lote_farmaceutico # K · qué clase de objeto es
es_de : antihipertensivo # K · de qué fármaco (concepto)
vence : 2027-09-30 # T · caducidad del lote
custodia : farmacia_central # Q · quién lo guarda
# La cadena de custodia: tres situaciones encadenadas, cada una con su momento
(prescrip_8842) ∈ O # ya existía: la doctora ordena (consulta de hoy)
(dispensa_9133) ∈ O
instancia_de : dispensacion # K
cumple : prescrip_8842 # M · qué orden satisface
agente : farmacia_central # Q · quién dispensa
lote_entregado: lote_av2207 # O · qué lote concreto sale
cantidad : 14 # N · unidades entregadas
inicio : 2026-06-14T12:05-05:00 # T
(adm_farmaco_9120) ∈ O
instancia_de : administracion_farmaco # K
cumple : dispensa_9133 # M · qué dispensación consume
agente : enf_rojas # Q · quién la aplica
paciente : maria_g # Q · a quién
lote_usado : lote_av2207 # O · trazabilidad del lote hasta el cuerpo
parte_de : ingreso_9120 # M · ocurre dentro de la hospitalización
inicio : 2026-06-14T20:00-05:00 # T
La cadena se lee de un tirón siguiendo los cables cumple: la administración
consume una dispensación, que a su vez satisface una prescripción. No hay tablas que cruzar
ni claves que adivinar.
Y como los tres eslabones apuntan al mismo lote_av2207, la pregunta del retiro
se contesta de una sola pasada.
# Retiro de lote: ¿a qué pacientes llegó algo de lote_av2207?
afectados = u.subjects_where("lote_usado", lote_av2207, role="paciente")
# → [maria_g, ...] en segundos, cruzando clínica y farmacia sin un solo JOIN
Cross-módulo sin pegamento
Clínica y farmacia son «módulos» distintos solo en la cabeza del
organigrama. En el grafo son el mismo tejido: la receta vive en el módulo clínico, el lote
en el de farmacia, y el cable cumple los une sin que nadie escriba código de
integración. La trazabilidad del lote es a la farmacia lo que la del mineral será a la
minera.
O encadenadas
por cumple). El lote concreto (lote_av2207) atraviesa la
dispensación y la administración, de modo que un retiro de lote se resuelve con una sola
proyección, sin cruzar tablas entre el módulo clínico y el de farmacia.Del paciente a la población
Todo este capítulo diseccionó a una paciente. Gonzales tiene nombre, una fibrilación en febrero, un diagnóstico que empeoró en marzo.
Pero quien dirige el hospital rara vez pregunta por Gonzales. Pregunta por la población que ella integra. Cuántos pacientes arrastran hoy una hipertensión grado 2. Qué diagnóstico encabezó el trimestre. Cuántas camas sigue ocupando cardiología esta mañana.
Y ahí está el premio que no se ve mientras modelas: ninguna de esas preguntas pide una tabla nueva. El diagnóstico de Gonzales es una situación más, del mismo tipo que los de los otros mil pacientes, y contar los de un tipo es contarlos todos a la vez.
Diseccionar con cuidado una sola consulta dejó armado, sin buscarlo, el tablero epidemiológico.
# Cuántos diagnósticos de hipertensión grado 2 hay vigentes — la cohorte que Gonzales integra
count(u, Pattern(fixed={"diagnostico_asignado": u.ind("hta_grado_2")},
type_constraint=u.ind("diagnostico")))
El lexicon de la clínica
Para que la doctora no tenga que aprender jerga de bases de datos, cargamos el lexicon con las palabras exactas de la medicina.
El lexicon es el traductor del que habló la Parte IV: pasa el vocabulario humano a los roles del catálogo y decide qué significa cada palabra según su compañía. El verbo «controlar», por ejemplo, quiere decir cosas distintas según lo que lo acompañe.
lex.register(LexiconEntry(
verb="controlar",
situation_type="consulta_cardiologia",
obligatory=["agente", "paciente"],
pattern=("a_un_paciente",), # "controlar a un paciente" → seguimiento clínico
))
lex.register(LexiconEntry(
verb="controlar",
situation_type="medicion_signo_vital",
obligatory=["agente", "medida_evaluada"],
pattern=("un_signo",), # "controlar la presión" → una medición
))
Y le instalamos el dialecto de la casa: un mapa entre las palabras que el personal clínico usa de verdad y las etiquetas del catálogo.
El usuario final nunca toca esas etiquetas. El sistema traduce por debajo, igual que el spa traducía «IGV» a su clase de impuesto.
lex.register_domain_dialect("cardiologia_central", {
"presión": "presion_arterial",
"el paciente": "paciente",
"receta": "prescripcion_medica",
"control": "consulta_cardiologia",
"alergia": "contraindicacion_clinica",
"la pastilla": "antihipertensivo",
})
Gracias a eso, la doctora puede dictar «controlé al paciente, la presión salió alta, le subí la pastilla y lo cito en un mes», y el grafo lo traduce a sus identificadores sin que ella sepa que existen. La interfaz es su idioma.
El antes y el después: del expediente fragmentado al grafo único
Antes, en SQL. En un sistema hospitalario típico, el expediente de Gonzales vive
repartido en cinco o seis tablas que no se hablan solas: pacientes,
consultas, diagnosticos, prescripciones,
contraindicaciones y, si el equipo fue cuidadoso, una
diagnostico_historial para guardar los cambios.
¿La doctora quiere saber si el ajuste que acaba de recetar choca con una contraindicación
vigente? Hay que cruzar prescripciones con
contraindicaciones. ¿Y si la hipertensión sigue activa? Otro JOIN
contra diagnostico_historial, filtrando por fechas.
La respuesta no está en ninguna tabla. Vive en el pegamento que el programador escribe y reescribe cada vez que cambia la lógica clínica.
-- Antes: el diagnóstico vigente vive en otra tabla, versionado por fechas;
-- la pregunta clínica obliga a encadenar JOINs y filtrar por rango temporal.
CREATE TABLE diagnosticos (id INTEGER PRIMARY KEY, paciente_id INT, codigo TEXT);
CREATE TABLE diagnostico_historial (id INTEGER PRIMARY KEY, diag_id INT,
grado TEXT, valido_desde DATE, valido_hasta DATE);
CREATE TABLE prescripciones (id INTEGER PRIMARY KEY, paciente_id INT, farmaco_id INT);
SELECT h.grado
FROM diagnostico_historial h
JOIN diagnosticos d ON d.id = h.diag_id
WHERE d.paciente_id = :paciente
AND h.valido_desde <= :fecha -- la lógica temporal,
AND (h.valido_hasta IS NULL OR h.valido_hasta > :fecha); -- a mano, cada vez
Después, en WQuestions. La misma información es un solo grafo de hechos mínimos.
diag_hta_8842 cuelga de consulta_8842 con parte_de y
lleva sus propias fechas de validez. prescrip_8842 apunta a
regla_renal_alerta con verificado_contra.
La pregunta se contesta mirando el grafo con un filtro de fecha: el motor devuelve solo los hechos cuya ventana de validez cubre el día consultado.
No hay JOIN ni código de pegamento. La vigencia y las causas ya venían tejidas
desde el primer hecho.
# Después: el diagnóstico vigente a una fecha es una proyección con filtro temporal.
vigente = u.value_at(maria_g, "diagnostico_asignado", at="2026-04-15") # → hta_grado_1
En medicina, un diagnóstico no es un campo de texto: es una creencia fechada, con su evidencia detrás y su caducidad delante. Tratarlo como una entidad, y no como una columna que se sobrescribe, es lo que convierte un expediente en algo que un juez puede leer.La lección de la clínica
Cuánto pesó el dominio entero
Vale la pena medir la huella, porque desmiente el prejuicio de que tanta expresividad cuesta un diluvio de datos.
Toda la consulta de Gonzales cabe en un puñado modesto de hechos: las cinco piezas, los tres porqués de la receta, los dos diagnósticos con su historia, la contraindicación y el control previsto. Un esquema relacional necesita bastante más para sostener la misma memoria.
La pepita metodológica: el arte de saber qué reificar
Llegamos a la tercera pregunta, la que dejamos pendiente al abrir el capítulo.
Al diseñar un dominio nuevo, ¿cómo decides qué dato merece volverse una entidad con
identidad propia en O, y cuál se queda como un número callado en N
o una etiqueta quieta en K?
La regla, en una línea
Si crees que en el futuro alguien va a hacer una pregunta o una afirmación sobre ese dato, reifícalo. Si nadie va a interrogarlo nunca, déjalo como valor.
Es una regla simple y brutal, y se aplica caso por caso. Mira cómo decide cada pieza de esta consulta su propio destino:
¿Reificamos el síntoma? Sí. Mañana el médico querrá saber cuándo empezó, qué tan
intenso era y si mejoró. Se vuelve entidad en O.
¿Reificamos la medición de presión? Sí. Mañana la conectaremos como evidencia de un
diagnóstico. Entidad en O.
¿Reificamos la contraindicación? Sí. Tiene autor, fecha de vigencia y condición
disparadora; alguien la consultará. Entidad en O.
¿Reificamos «cada mañana»? No. Es un valor terminal. Nadie va a interrogar al
concepto «cada mañana». Se queda como etiqueta en K.
¿Reificamos «20 mg»? No. Es una cantidad con su unidad. Vive en N y
ahí muere.
¿Reificamos «148/95»? El número, no; pero la medición que lo contiene, sí
(porque la medición sí será interrogada).
Convertir algo en entidad cuesta unos pocos bytes. No hacerlo cuesta mucho más: años después un regulador pide el historial completo de un dato que guardaste como texto plano, y toca rehacer medio sistema.
En medicina, además, se paga en algo peor que dinero. Por eso, ante la duda, la regla se inclina siempre a favor de la entidad.
Balance: un dominio nuevo, casi sin fricción
Cerremos repasando qué demostró el prototipo al absorber, desde cero, un dominio para el que la arquitectura no había sido diseñada.
El veredicto de la clínica
- La carpeta maestra funcionó. La consulta abrazó sus
cinco sub-situaciones con
parte_de, igual que la venta abrazó sus líneas. Ni una tabla paralela, ni un esquema nuevo. - La única fricción fue sana. El error de firma al
mezclar
OconKno fue un fallo del modelo: fue el modelo corrigiendo al modelador. Se resolvió declarando un puñado de cables de dominio. - El diagnóstico se modeló completo. Su duda
(modalidad), su evidencia (
motivado_por) y su caducidad (D6) se guardaron en dimensiones separadas, sin aplastarse en un campo de texto. - La historia se preserva (D6). Dos diagnósticos contrarios conviven sin que se pierda el rastro forense. El sistema puede responder qué se sabía en cualquier fecha pasada.
- El método quedó explícito. Evento ancla, piezas que nacen dentro, y la regla de qué reificar. Esa receta de elicitación sirve para el próximo dominio, sea cual sea.
La clínica parecía pedir una arquitectura propia y cupo en la misma de siempre, con un par de cables nuevos y ninguna excepción estructural.
Pero aquí asomó una exigencia que el próximo capítulo convierte en ley: que varios custodios, en hospitales distintos, puedan leer y escribir sobre el mismo paciente sin pisarse.
Subimos al dominio más implacable de todos. Un banco, donde no borrar el pasado deja de ser buen gusto y pasa a ser una orden del regulador.