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 un consultorio de cardiología. El paciente (el mismo Vega que meses atrás entró por urgencias con una fibrilación) llega ahora a un control de rutina. No hay drama: se sienta, cuenta que duerme mal y que a veces siente el corazón «a destiempo», la doctora le toma la presión, repasa su última analítica, confirma que la hipertensión que arrastra desde el episodio agudo sigue ahí pero algo peor, ajusta la dosis de un fármaco, anota una contraindicación que el paciente no conocía y agenda otro control en treinta días. Quince minutos. Cuando Vega sale por la puerta, la cita ya terminó; pero casi nada de lo que importa terminó con ella. El diagnóstico seguirá vigente un año, la prescripción habrá que reevaluarla mes a mes, la alergia recién descubierta deberá gritar cada vez que alguien intente recetarle ese fármaco. Esos quince minutos dejaron un sedimento que un médico distinto, en un hospital distinto, dentro de cinco años, tendrá que poder leer sin ambigüedad. Ese sedimento es el examen de este capítulo.
Hasta aquí, la Parte V ha modelado negocios cuyo corazón es la transacción. Una sesión de spa empieza, termina, se cobra y el mundo sigue girando; un viaje en taxi ocurre, se paga y se archiva. Modelarlos fue, en buena medida, aprender a usar bien las herramientas y luego repetir la fórmula cambiando las palabras del lexicon. La medicina no concede esa comodidad. Una consulta es un evento, sí, pero a nadie le interesa cuánto duró: lo que interesa es el contenido 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 engendró.
Por eso este capítulo cambia de foco. No vamos a presumir de soluciones ya hechas: vamos a mostrar cómo se modela un dominio nuevo desde cero. La medicina es el banco de pruebas perfecto para esa metodología porque es un campo en el que nadie llega con el esquema resuelto: hay que elicitarlo, decisión a decisión, viendo dónde la intuición humana acierta y dónde la rigidez del 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: una consulta médica completa (síntoma, medición, diagnóstico, prescripción y control futuro, con su incertidumbre clínica, su evidencia y su vigencia en el tiempo) cae sobre los mismos siete ejes, las mismas situaciones reificadas y el mismo lexicon que ya conoces. La fricción será mínima. Donde la haya, 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 que uno le hace al negocio, en este orden, antes de tocar el teclado. Son la columna vertebral de la metodología, y conviene enunciarlas porque 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 pregunta es la más sutil y la dejaremos para el final del capítulo, porque es la que de verdad separa a quien modela bien de quien acumula campos. Por ahora basta con 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 : vega # 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 sub-situaciones,
exactamente como la venta del spa contenía sus líneas. Que la consulta merezca reificarse no
es un capricho (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 que vuelve fascinante a la medicina no es el contenedor, sino el
interior de cada pieza.
vega 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 el prototipo de este dominio, y vale la pena contarla porque enseña más que cualquier acierto. La intuición humana, al modelar la medición de presión, dice: «el tema de esta medición es la presión arterial». Y al modelar la receta: «el tema de esta prescripción es el fármaco». Parece obvio.
Pero detente. «Presión arterial» y «el antihipertensivo» no son objetos físicos 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 Vega compra en la
farmacia sí es un objeto del eje O (tiene lote, vencimiento, ubicación), pero
el concepto científico del fármaco es una clase, un habitante del eje
K. El instinto humano mezcla, sin notarlo, lo físico con lo conceptual.
El catálogo estricto del modelo no se deja engañar. El cable tema tiene una
firma que solo admite conectar O con O. Si intento usarlo para
apuntar de una medición (en O) hacia la magnitud presión (en K),
el sistema aborta con un error de firma 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 cuya firma exige O→O lanza un SignatureError.
No es un estorbo: es la frontera que impide que un dato mal tipado entre al grafo. El
error no estaba en el modelo; estaba en mi cabeza, que confunde el objeto concreto con la
idea abstracta todo el tiempo. La rigidez de las matemáticas me salvó de un desastre
semántico que más tarde habría confundido a cualquier máquina que leyera el expediente.
¿La salida? No forzar el cable genérico, sino declarar cables de dominio: roles
propios de la medicina, diseñados de fábrica para apuntar hacia el eje K. Son
parte de la elicitación: 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 incertidumbre clínica, decoramos la situación con su modalidad epistémica y un estado factual que 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
Esta es la misma distinción que en el spa separaba la venta real de la mera intención de compra, o que en banca separa una solicitud de un préstamo desembolsado. Que un dato pueda ser «todavía no seguro» sin por eso ser falso es una necesidad que aparece en cada 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 de causa y efecto no se pierde en un comentario: se ata con un cable causal. Tal como argumentó el capítulo del «por qué», no hay un eje «por qué»; el porqué se reparte en cables distintos, y aquí el que corresponde es el que apunta a la razón que motivó la conclusión.
(diag_hta_8842, motivado_por, medicion_8842) # M · la medición es la evidencia
Con ese único cable, la medición deja de ser un número flotando y se vuelve la evidencia del diagnóstico. Si un auditor médico o una máquina revisan el expediente y preguntan «¿en qué se basó este diagnóstico?», la respuesta no exige interpretar prosa: se lee siguiendo el cable. La justificación viaja con el dato.
3 · El viaje en el tiempo
Esta es la dimensión que separa el software hospitalario de verdad del software de juguete. Los diagnósticos caducan y mutan. Supongamos que tras el episodio agudo, en marzo, a Vega se le asignó hipertensión de grado 1. En esta consulta de junio la doctora confirma que empeoró: ahora es grado 2. Si se reescribiera el diagnóstico viejo encima del nuevo, se borraría la historia del paciente —un crimen, no solo de negligencia clínica, sino de imposibilidad forense—.
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 de modelarlo así es una capacidad forense que 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 de datos no devuelve el estado de hoy: devuelve exactamente la verdad clínica que regía en abril (grado 1), ignorando todo lo que se supo después. Una consulta con un filtro temporal basta.
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 a la vez varias de las fuerzas causales que el modelo distingue. Una receta no es un dato suelto: es una decisión con un motivo, una finalidad y un control de seguridad, y el modelo guarda cada uno en su propio cable en lugar de fundirlos en un comentario.
pres = ingest_situation(u, lex, "prescribir",
roles={
"agente": dra_navarro,
"paciente": vega,
"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 profundas a tres preguntas distintas. La doctora no receta por gusto: lo hace motivada por el diagnóstico, con la finalidad de llevar la presión a una meta, y verificando contra un manual de farmacología que el ajuste no dañe los riñones de un paciente que ya viene comprometido. 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 es una línea escondida en el código de la aplicación. Es un evento
reificado 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. Vive en el
grafo, a la vista, y por eso es auditable.
(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 viviendo en el grafo, la base de datos se vuelve inteligente sin volverse rígida. Cuando la doctora presiona «recetar», un motor externo (o una IA) escanea el grafo, encuentra esta norma, comprueba la función renal del paciente y, si hace falta, levanta una alerta antes de que el daño ocurra. 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 una sutileza importante. Todavía no ocurrió: es un plan. Si el sistema lo guardara como un hecho consumado, contaminaría cualquier informe (contaríamos como «atendida» una cita que no existe). El modelo lo marca como previsto, no como real, exactamente con la misma maquinaria de modalidad que usamos para el diagnóstico sospechado o para la intención de compra del spa.
(control_8842) ∈ O
instancia_de : consulta_cardiologia
paciente : vega
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 único rótulo, el sistema responde sin tropezar tanto «¿qué citas tiene Vega agendadas?» (donde el control aparece) como «¿cuántos pacientes atendió la doctora en junio?» (donde no aparece, porque aún no sucedió). Lo previsto y lo real conviven en el mismo grafo sin confundirse.
La historia clínica como serie temporal
Hasta aquí hemos diseccionado una consulta. Pero Vega no es una consulta: es un
paciente con años de roce con el sistema sanitario. El mismo Vega que entró por urgencias con
una fibrilación, el que en marzo recibió su primer diagnóstico de hipertensión, el que hoy
vuelve al control de cardiología, y el que (lo veremos enseguida) pasará unos días ingresado.
Su identidad es una sola, cosida con el mismo vega que ya recorre la tienda y la
clínica; lo que cambia es el rosario de situaciones que cuelgan de ella a lo largo del
tiempo. Eso es una historia clínica: no un documento, sino una serie
temporal de episodios.
En el modelo, la historia no es una tabla con una fila por visita. Es la proyección de todas
las situaciones cuyo paciente es vega, ordenadas por su 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 reificada más en O que
referencia al mismo paciente y se sitúa en el tiempo. Recuperar «la historia de Vega» es
barrer el grafo por ese nodo y leer la cinta cronológica.
# Cada episodio es una situación que apunta al MISMO paciente, situada en T
(urgencias_2403, paciente, vega) # T: 2026-02-14 · la fibrilación
(analitica_2511, paciente, vega) # T: 2026-03-05 · sangre y lípidos
(consulta_3019, paciente, vega) # T: 2026-03-12 · 1er dx de HTA grado 1
(consulta_8842, paciente, vega) # T: 2026-06-09 · el control de hoy
(ingreso_9120, paciente, vega) # 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(vega, valid_at="2026-06-19")
La clave es que esa cinta es bitemporal: no solo registra cuándo
ocurrió cada episodio (el tiempo del eje T), sino 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 podemos
preguntar dos cosas distintas: «¿qué le pasó a Vega en abril?» (un corte por el tiempo del
hecho) y «¿qué creía saber el hospital sobre Vega en abril?» (un corte por el tiempo
del registro). Un expediente de juguete confunde ambas; el grafo las distingue de fábrica.
vega, 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 el paciente refiere mareos. La doctora decide ingresarlo unos días para vigilancia. Y aquí aparece una estructura que la consulta ya insinuó pero 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 administrada, la evolución diaria) hasta que se cierra con el alta.
El instinto erróneo 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 fresco, y todo lo
que ocurre dentro le cuelga con el mismo 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 : vega # 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 (tiene
ubicación, ocupación, mantenimiento), no una etiqueta. Que el ingreso la referencie por
L/O y no la copie como texto es lo que permite responder «¿qué camas
están libres en cardiología ahora mismo?» sin inventar otra tabla. El servicio
(cardiologia), en cambio, es una clase en K: no se interroga 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 administrada el 14 de junio no necesita arrastrar «paciente Vega,
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 prescripción y el cuerpo de Vega hay una cadena de custodia que cruza el módulo clínico con el de farmacia, exactamente como en un ERP el módulo de ventas conversa con el de inventario. Tres situaciones distintas, encadenadas, cada una con su autor y su momento: la prescripción (la doctora ordena), la dispensación (la farmacia entrega un lote concreto) y la administración (la enfermería lo aplica al paciente).
El detalle que lo cambia todo es el lote. La farmacia no entrega «el
antihipertensivo» (un concepto en K); entrega una caja física de un lote
concreto, con su vencimiento y su trazabilidad, igual que en minería un saco de mineral
arrastra su lote de origen. Si mañana ese lote se retira por un defecto de fabricación, el
grafo debe poder 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, 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 : vega # 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 satisface una prescripción. No hay tablas que cruzar ni claves
foráneas que adivinar; la trazabilidad es el propio tejido del grafo. Y como cada eslabón
referencia el mismo lote_av2207, la pregunta forense del retiro de lote se
contesta con una sola proyección.
# Retiro de lote: ¿a qué pacientes llegó algo de lote_av2207?
afectados = u.subjects_where("lote_usado", lote_av2207, role="paciente")
# → [vega, ...] 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 prescripción 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. Es la misma lección que dará el capítulo del ERP, anticipada aquí: 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 un paciente. Vega tiene nombre, una fibrilación en febrero, un diagnóstico que cambió de grado en marzo. Pero quien dirige el hospital rara vez pregunta por Vega: pregunta por la población que Vega 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 dividendo que no se ve mientras modelas: ninguna de esas preguntas pide una tabla nueva. El diagnóstico de Vega es una situación más, del mismo tipo que los de los otros mil pacientes, y contar los de un tipo es contarlos a todos a la vez. Diseccionar con cuidado una sola consulta fue, sin proponérnoslo, dejar armado el tablero epidemiológico.
# Cuántos diagnósticos de hipertensión grado 2 hay vigentes — la cohorte que Vega 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 (o el sistema que ella usa) no tenga que aprender jerga de bases de datos, configuramos el lexicon con las palabras exactas de la medicina. El lexicon es el compilador del que habló la Parte IV: traduce el vocabulario humano a los roles canónicos y resuelve la polisemia. El verbo «controlar», por ejemplo, significa 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 del dominio: un mapa entre las palabras que el personal clínico usa de verdad y las etiquetas canónicas del catálogo. El usuario final nunca toca esas etiquetas internas (el sistema traduce por debajo, exactamente como 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 esto, la doctora puede dictarle al sistema «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 internos sin que ella sepa que existen. La interfaz es su idioma, no el catálogo (tal como dejó establecido la Parte IV).
El antes y el después: del expediente fragmentado al grafo único
Antes, en SQL. En un sistema hospitalario típico, el expediente de Vega vive
repartido en cinco o seis tablas que no se hablan solas: pacientes,
consultas, diagnosticos, prescripciones,
contraindicaciones y (si el equipo fue cuidadoso) una tabla
diagnostico_historial para versionar los cambios. Cuando la doctora quiere
saber si el ajuste que acaba de recetar choca con una contraindicación vigente, el
sistema debe cruzar prescripciones con contraindicaciones; y para
saber si la hipertensión sigue activa, otro JOIN contra
diagnostico_historial filtrando por fechas. La respuesta no está en ninguna
tabla sola: vive en el pegamento que el programador escribe y reescribe cada vez que la
lógica clínica cambia.
-- 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 grafo único de hechos atómicos:
diag_hta_8842 cuelga de consulta_8842 con parte_de,
lleva sus propias fechas de validez internas, y prescrip_8842 apunta a
regla_renal_alerta con verificado_contra. La pregunta (¿esta
prescripción choca con una contraindicación vigente?) es una proyección sobre el grafo con
un filtro temporal: el motor entrega solo los hechos cuya ventana de validez cubre la fecha
consultada. No hay JOIN entre tablas ni código de pegamento; la vigencia y las
relaciones causales ya estaban tejidas en el mismo tejido de datos desde el primer hecho.
# Después: el diagnóstico vigente a una fecha es una proyección con filtro temporal.
vigente = u.value_at(vega, "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 debe costar un diluvio de datos. Toda la consulta de Vega (las cinco piezas, los tres porqués de la receta, los dos diagnósticos versionados, la contraindicación y el control previsto) se guardó como un puñado modesto de hechos atómicos. Comparado con lo que un esquema relacional necesita para sostener la misma riqueza histórica, la diferencia es notable.
La pepita metodológica: el arte de saber qué reificar
Llegamos a la tercera pregunta de la elicitación, la que dejamos pendiente al abrir el
capítulo, porque es la que de verdad separa a quien modela bien. A la hora de diseñar un
dominio nuevo, ¿cómo decides qué dato merece convertirse en una entidad con identidad propia
en O y qué dato debe quedarse como un número callado en N o una
etiqueta inerte 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).
El costo de reificar es de unos pocos bytes en el servidor. El costo de no hacerlo (y descubrir, años después, que un regulador exige el historial completo de un dato que guardaste como texto plano) se mide en una refactorización carísima y, en medicina, en algo peor que dinero. Por eso, ante la duda, esta regla se inclina siempre hacia reificar.
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 exigir una arquitectura especializada y resultó caber en la misma que ya conocíamos, con un par de cables propios y ni una sola excepción estructural. Pero hubo una exigencia que aquí solo asomó (la de que varios custodios distintos, en hospitales distintos, puedan leer y escribir sobre el mismo paciente sin pisarse) y que en el próximo capítulo se vuelve la ley. 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 condición que dicta el regulador.