WQuestions

Parte V · En la práctica

18

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.

tripletas
(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.

consulta_8842 el evento ancla · O Q paciente vega Q agente dra_navarro L lugar_de consultorio_2 T inicio 09:40 · 9 jun síntoma lo que dice medición 148/95 diagnóstico HTA grado 2 prescripción 20 mg / día control previsto · +30 d parte_de M(O→O) Q los participantes · L el consultorio · T el momento · O / K las cinco piezas · M el cable que las cuelga del ancla.
Figura 18.1. La consulta reificada como evento ancla. Arriba, sus participantes repartidos en los ejes (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.

python
# 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
prescrip_8842O medicamento_prescritoM(O→K) antihipertensivoK

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.

tripletas
(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.

tripletas
(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.

python
# 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.

tiempo → mar 2026 abr 2026 jun 2026 hoy HTA grado 1 valid_from: mar · valid_to: jun HTA grado 2 valid_from: jun · sin fin rectifica consulta · at = abril devuelve → grado 1 El eje del tiempo es T; las dos verdades son clases en K · O; el cable que las une es M. Nada se sobrescribió.
Figura 18.2. La vigencia del diagnóstico (D6) sobre la línea de tiempo. El grado 1 fue válido de marzo a junio; el grado 2 lo sustituye desde junio, con su ventana abierta. El cable 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.

python
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.

tripletas
(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.

tripletas
(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.

tripletas
# 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 una sola identidad · Q tiempo → urgencias fibrilación 14 feb analítica 5 mar consulta dx HTA gr. 1 12 mar dx gr. 2 9 jun · hoy ingreso contenedor 14 jun paciente Todos los episodios cuelgan del mismo nodo Q; el orden lo da T; cada afirmación lleva su propia vigencia D6.
Figura 18.3. La historia clínica de Vega como serie temporal de episodios. La identidad del paciente (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.

tripletas
(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.

ingreso_9120 · la hospitalización (marco · O) 14 jun admisión 17 jun alta admisión cama 4B-307 signos por turno ronda visita médica medicación administrada evolución nota diaria parte_de M(O→O) Las paredes son el eje T (admisión → alta); el interior son eventos en O; el cable que los cuelga del marco es M.
Figura 18.4. La hospitalización como situación-marco. Las paredes verticales son el eje 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.

tripletas
# 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.

python
# 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
adm_farmaco_9120O cumpleM(O→O) dispensa_9133O cumpleM(O→O) prescrip_8842O

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.

prescripción prescrip_8842 dra_navarro · ordena dispensación dispensa_9133 farmacia · entrega administración adm_farmaco_9120 enf_rojas · aplica cumple cumple lote_av2207 · vence 2027-09 · trazabilidad el mismo objeto físico atraviesa dispensación y administración Tres situaciones en O encadenadas por M (cumple); el lote, objeto en O clasificado por K, las cruza para la trazabilidad.
Figura 18.5. La cadena de la farmacia interna. La administración de la enfermería cumple una dispensación de la farmacia, que a su vez cumple la prescripción de la doctora (tres situaciones en 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.

python
# 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.

python
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).

python
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.

sql
-- 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.

python
# 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.

Figura 18.6. Huella de la consulta por bloque, en hechos atómicos. La pieza más cara es el diagnóstico, justamente porque carga la vigencia (D6): guardar dos verdades históricas en vez de pisar una sola cuesta unos hechos de más —y vale cada uno—. El total ronda las seis decenas de tripletas: un volumen ridículo frente a la maraña de tablas, historiales y procedimientos que el mismo caso exige en SQL.

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 O con K no 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.