WQuestions

Parte V · En la práctica

21

Una universidad

Aquí la dificultad no es el volumen ni la ley, sino la forma: el saber se ordena en un grafo de dependencias y una vida académica dura décadas. Veamos si el modelo sabe recorrer caminos.

Es lunes de matrícula y Tomás Quiroz tiene quince navegadores abiertos. Cursa el cuarto semestre de Ciencia de la Computación y quiere inscribirse en Algoritmos, el curso que todos dicen que «abre puertas». El portal de matrícula lo rechaza con un mensaje escueto: «No cumple prerrequisitos». Pero Tomás está seguro de haber aprobado lo que hacía falta. ¿Le falta Estructuras de Datos, que aprobó el ciclo pasado? ¿O es la rama de matemática, Cálculo, que arrastra desde primero? El sistema no se lo dice: solo sabe responder sí o no, nunca por dónde. Y detrás de ese silencio se esconde el problema técnico que define a una universidad como dominio.

Porque una universidad no se parece a un comercio ni a un banco. Sus dos rasgos propios son de otra naturaleza. El primero: los tiempos son largos. Una carrera dura cinco años, pero el historial de un egresado lo acompaña toda la vida: la nota de un curso que rindió a los veinte le sirve para un posgrado a los cuarenta. El segundo, y el que da título a este capítulo: las cosas dependen unas de otras. No puedes tomar Algoritmos sin antes haber pasado por Estructuras de Datos, y a esa no llegas sin Programación. La malla curricular es, literalmente, un grafo de dependencias.

Cualquier sistema académico serio tiene que poder responder, sin sudar, preguntas como estas:

  • ¿Qué cursos puede tomar Tomás este semestre, dado lo que ya aprobó?
  • ¿Qué nota sacó Lucía en Cálculo I antes de su reclamo? ¿Y después de la rectificación?
  • ¿Quiénes seguían matriculados en Bases de Datos el 1 de mayo?
  • ¿Qué cadena de prerrequisitos arrastra Aprendizaje de Máquina, y cuáles de ellos le faltan a Tomás?
  • ¿Quiénes integraron el jurado de la tesis de Renata?

En una base relacional clásica, cada una de estas preguntas pide algo distinto: una tabla histórica aquí, un WITH RECURSIVE allá, un procedimiento almacenado que replica en código la lógica del recorrido. En WQuestions, como veremos, cada una es un recorrido de uno o dos saltos sobre el mismo grafo de hechos. No hay máquina distinta para cada pregunta: hay un solo mapa y muchas rutas sobre él.

La universidad sobre las siete coordenadas

Antes de los casos, repartamos las piezas del mundo académico entre los ejes de valor. El ejercicio ordena de un golpe lo que en un sistema heredado vive disperso en una veintena de tablas:

Q  quién · agentes

Estudiantes, docentes, autoridades, miembros de jurado y la propia universidad como persona jurídica. Una sola persona puede aparecer en muchos roles: Renata es estudiante, jefa de práctica y tesista a la vez.

O  qué · entidades y eventos

Carreras, planes, cursos, matrículas, evaluaciones, reclamos, tesis, defensas y graduaciones. Cada uno con identidad propia y trazabilidad. Aquí vive el grueso del peso académico.

L  dónde · lugares

Facultades, aulas, laboratorios, auditorios y campus. Forman jerarquías como cualquier organización territorial: el aula es parte del pabellón, el pabellón del campus.

T  cuándo · tiempos

Inicio y fin de cada ciclo, momento exacto de una matrícula, fecha de un examen, día de una defensa. El reloj académico es largo y no olvida: una nota de hace veinte años sigue siendo consultable.

N  cuánto · magnitudes

Créditos, notas numéricas, horas semanales, montos de pensión. Cada magnitud arrastra su unidad: cuatro créditos no son cuatro puntos ni cuatro horas.

K  cuál · clases

Tipos de carrera, estados de matrícula (vigente / retirado), modalidades de evaluación y niveles cualitativos (aprobado / desaprobado). El zócalo categórico que da sentido al resto.

Y el séptimo eje, M (el cómo), aporta los cables que amarran todo: parte_de arma las jerarquías, requiere_prereq teje la malla, agente ata cada persona a su situación. Sin esos enlaces, las seis cajas anteriores serían seis listas inertes. Con ellos, una vida académica entera se vuelve un grafo navegable. Recorrámoslo.

Caso 1 · La estructura académica como jerarquía

El plan de estudios de Tomás tiene una forma de árbol que el modelo absorbe sin esfuerzo. La carrera contiene años; cada año, ciclos; cada ciclo, cursos. Una sola relación, parte_de, expresa los cuatro niveles:

tripletas
(carrera_cc) ∈ O                         # Ciencia de la Computación
(plan_2024)        parte_de  carrera_cc        # la malla vigente desde 2024
(ciclo_2026_i)     parte_de  plan_2024         # el ciclo en curso
(cc_310_algoritmos) parte_de ciclo_2026_i      # un curso del ciclo
(cc_310_algoritmos) creditos  n_4_cr           # arrastra su magnitud (N)
(cc_310_algoritmos) docente   prof_salazar     # apunta a un agente (Q)
(cc_310_algoritmos) dictado_en lab_b2          # y a un lugar (L)

Cada nivel es una entidad en O, y es parte de el nivel superior. Tres tripletas de jerarquía y la columna vertebral de la carrera queda armada. Cuando Tomás pregunta «¿qué cursos hay en mi ciclo actual?», la consulta es un único salto: trae todas las entidades de O cuyo parte_de sea ciclo_2026_i. Y cada curso, además de colgar de su ciclo, lleva sus propios atributos (créditos, docente, aula, código, sílabo) sin que ninguno necesite una tabla aparte. Todo el inventario académico tiene la misma forma.

cc_310_algoritmosO parte_deM(O→O) ciclo_2026_iO parte_deM(O→O) plan_2024O

Caso 2 · Los prerrequisitos como grafo dirigido acíclico

Llegamos al corazón del capítulo. La malla curricular (qué curso exige haber pasado por cuál) es por su propia naturaleza un grafo dirigido acíclico, un DAG: las aristas tienen sentido (de requisito a curso), no hay ciclos (ningún curso puede exigirse a sí mismo, ni directa ni indirectamente) y las dependencias se cruzan (un curso puede tener varios requisitos, y un requisito puede habilitar varios cursos).

DAG · grafo dirigido acíclico

Un conjunto de nodos unidos por flechas con sentido, sin que ninguna ruta te devuelva al punto de partida. Es la estructura natural de toda dependencia ordenada: las tareas de un proyecto, las versiones de un documento, las migraciones de una base de datos —y los prerrequisitos de una carrera—. Que no haya ciclos es justo lo que garantiza que siempre exista un orden válido para avanzar.

En un sistema relacional, esto se modela con una tabla curso_prereq(curso, prereq) y se consulta con SQL recursivo. En WQuestions, cada prerrequisito es una sola tripleta. Tomamos un fragmento real de la malla de Tomás (dos líneas que confluyen, la de matemática y la de programación):

tripletas
# línea de programación
(cc_210_estructuras) requiere_prereq  cc_101_progra
(cc_220_basesdatos)  requiere_prereq  cc_210_estructuras
(cc_310_algoritmos)  requiere_prereq  cc_210_estructuras

# línea de matemática
(ma_120_calculo)     requiere_prereq  ma_110_discreta
(ma_230_probabilidad) requiere_prereq ma_120_calculo

# el curso que las une: necesita las DOS ramas a la vez
(cc_310_algoritmos)  requiere_prereq  ma_120_calculo
(cc_420_aprendizaje) requiere_prereq  cc_310_algoritmos
(cc_420_aprendizaje) requiere_prereq  ma_230_probabilidad

Algoritmos (cc_310) exige dos requisitos simultáneos (uno de cada rama), y Aprendizaje de Máquina (cc_420), la cima de la carrera, exige otros dos. El modelo lo absorbe sin pestañear porque requiere_prereq es un cable múltiple: un mismo curso puede emitir varias flechas de requisito, cada una su propio hecho atómico, independiente de las demás. No hay que inventar una «tabla de dependencias compuestas»; basta apilar tripletas.

rama · programación rama · matemática CC-101 Progra. CC-210 Estruct. CC-220 BB.DD. MA-110 Discreta MA-120 Cálculo MA-230 Probab. CC-310 Algoritmos CC-420 Aprend. Máquina
Figura 21.1. La malla de Tomás como grafo dirigido acíclico. Cada curso es un individuo de O; cada flecha es una tripleta requiere_prereq (en color cómo). Las dos ramas (programación y matemática) confluyen en Algoritmos, que requiere ambas a la vez, y la carrera culmina en Aprendizaje de Máquina, que depende de Algoritmos y de Probabilidad. Cada dependencia es un hecho atómico independiente.

Ahora podemos resolver el drama del lunes. La pregunta «¿qué cursos puede tomar Tomás este ciclo?» se vuelve un recorrido directo sobre el grafo. Para cada curso del ciclo, el motor mira sus flechas requiere_prereq y verifica que todos los requisitos tengan, en el historial de Tomás, una evaluación con estado aprobado. Si falta uno solo, el curso queda excluido. Y (esto es lo que el portal del lunes no sabía hacer) el mismo recorrido puede devolver el requisito que falta, no solo un «no».

El recorrido de elegibilidad, en una frase

Un curso es elegible para un estudiante si, y solo si, el conjunto de los destinos de sus aristas requiere_prereq está contenido en el conjunto de cursos que ese estudiante aprobó. Es una operación de conjuntos sobre el grafo: sin join, sin SQL recursivo, sin procedimiento almacenado. La diferencia entre los dos conjuntos es, además, la lista exacta de lo que le falta.

Apliquémoslo. Tomás aprobó Programación, Estructuras de Datos y Discreta, pero no Cálculo. Algoritmos exige cc_210_estructuras ✓ y ma_120_calculo ✗. El recorrido devuelve un único faltante: Cálculo. El portal podría haberle dicho, en vez de un «no» mudo: «Te falta Cálculo I para habilitar Algoritmos». El grafo conocía la respuesta desde el principio; solo había que recorrerlo en lugar de comparar banderas.

Caso 3 · La matrícula que cambia de estado sin perder el pasado

Tomás se matricula en Bases de Datos el 10 de marzo. Lucía también, dos días después. Pero a mediados de abril Lucía se retira del curso. ¿Cómo guardamos esto sin perder información? La tentación clásica (y el error más común) es poner una columna estado en la tabla de matrículas y actualizarla cuando alguien se retira. El problema aparece en julio, cuando la secretaría pregunta: «¿quiénes estaban matriculados el 1 de abril?». La respuesta fiel ya no existe: el UPDATE borró el estado anterior.

En WQuestions los dos estados conviven en el grafo, separados por vigencia. No se sobrescribe nada: se cierra el intervalo del estado viejo y se abre el del nuevo.

D6 Vigencia: el pasado no se sobrescribe

Como vimos al modelar el banco, ningún atributo que pueda cambiar se guarda como un valor desnudo, sino con un intervalo [inicio, fin). Cambiar el estado de una matrícula no es modificar una celda: es cerrar el intervalo vigente y abrir uno nuevo. La consecuencia es que el grafo conserva, gratis, toda la trayectoria de la matrícula a lo largo del tiempo.

tripletas
(matricula_lucia_bd, estado, vigente,
                     inicio=2026-03-12, fin=2026-04-18)
(matricula_lucia_bd, estado, retirada,
                     inicio=2026-04-18, fin=hoy)

La pregunta «¿estaba Lucía matriculada el 1 de abril?» se responde directo: una consulta con al=2026-04-01 filtra por vigencia y devuelve vigente. La misma consulta con al=2026-05-01 devuelve retirada. Sin tabla histórica auxiliar, sin esfuerzo extra. La matrícula nunca se borra: cambia de estado y el historial queda fechado para siempre.

Caso 4 · Una persona, muchos roles

Una verdad incómoda del mundo académico: las personas no son una sola cosa. Renata Ferro es estudiante de quinto año y, al mismo tiempo, jefa de práctica del curso de Programación. En unos años será docente titular; más adelante, directora de tesis; quizá, decana. Es la misma persona (un solo individuo en Q), pero ocupa roles distintos en situaciones distintas.

En un sistema tradicional esto se vuelve un dolor de cabeza: una tabla estudiantes, otra docentes, claves cruzadas y un proceso de sincronización para el día en que un estudiante se convierte en profesor. En WQuestions el problema no existe, y la razón es una decisión de diseño que ya conoces:

D5 Agencia contextual

El rol de agente lo determina el verbo de la situación, no un «tipo» fijo de la persona. Renata es renata_q: aparece como agente en una matrícula (rol estudiante), como agente en una asignación docente (rol jefa de práctica), como agente en una tesis (rol tesista). El sistema no distingue entre tipos de personas; distingue entre tipos de situaciones. Cada rol vive en su situación.

tripletas
# Renata como estudiante
(matricula_renata_ml, agente, renata_q)
(matricula_renata_ml, tema,   cc_420_aprendizaje)

# Renata como jefa de práctica
(asignacion_jp_2026, agente, renata_q)
(asignacion_jp_2026, rol,    rol_jefe_practica)     # ← rol de dominio (K)
(asignacion_jp_2026, tema,   cc_101_progra)

# Renata como tesista
(tesis_renata, agente, renata_q)
(tesis_renata, instancia_de, defensa_tesis)

Cuando alguien pregunta «¿qué hizo Renata este año?», la consulta es una sola: trae todas las situaciones donde renata_q sea agente y proyecta su instancia_de. La respuesta sale del grafo de forma natural y abarca lo académico, lo docente y lo investigativo en una sola lista. No hubo que unir tres tablas de tres «tipos» de persona, porque nunca hubo tres tipos: hubo una persona y tres situaciones.

Caso 5 · La cadena nota → reclamo → rectificación

Llegamos al caso emblemático de la trazabilidad académica. Lucía rinde el examen final de Cálculo I el 15 de julio. La Dra. Bravo corrige y le pone 12. Lucía revisa, no está de acuerdo con la corrección de un ejercicio y presenta un reclamo formal el 20 de julio. La docente lo revisa, le da la razón y el 25 de julio rectifica la nota a 15.

En un sistema tradicional, la nota se sobrescribe. El historial (si existe) vive en una tabla auxiliar que casi nadie consulta. Cuando años después alguien quiere reconstruir el incidente (un decano que atiende una queja, un comité de calidad que audita), el rastro está borroso. En WQuestions, las tres situaciones conviven en el grafo, y la causa que las encadena queda explícita.

Aquí entra en juego una decisión que el libro ya estableció: el «por qué» no es un eje, sino una relación entre hechos, repartida en cuatro cables distintos.

D7 El porqué, repartido en cuatro cables

No hay un eje «por qué»: la causalidad se expresa con causado_por, motivado_por, con_finalidad y justificado_por. La rectificación está motivado_por el reclamo (esa fue su razón) y rectifica la evaluación original (ese es su blanco). La graduación, más adelante, estará justificado_por la defensa. El audit trail no es una tabla aparte: es la propia topología del grafo.

tripletas
# 1. la evaluación inicial (situación reificada)
(eval_lucia_calc) ∈ O
  instancia_de: evaluar_examen
  agente:       dra_bravo
  paciente:     lucia_q
  tema:         ma_120_calculo
  momento:      2026-07-15

# 2. el reclamo: otra situación, agente = Lucía
(reclamo_lucia) ∈ O
  instancia_de: reclamar_nota
  agente:       lucia_q
  tema:         eval_lucia_calc
  momento:      2026-07-20

# 3. la rectificación: causa explícita y blanco explícito
(rectif_lucia) ∈ O
  instancia_de:  rectificar_nota
  agente:        dra_bravo
  motivado_por:  reclamo_lucia        # ← por qué se hizo
  rectifica:     eval_lucia_calc      # ← qué corrige
  momento:       2026-07-25

¿Y la nota vigente? Cambia con la misma vigencia D6 del Caso 3. La calificación era 12 entre el 15 y el 25 de julio; desde el 25 es 15. Las dos versiones existen, fechadas:

tripletas
(eval_lucia_calc, nota_vigente, n_12,
                  inicio=2026-07-15, fin=2026-07-25)
(eval_lucia_calc, nota_vigente, n_15,
                  inicio=2026-07-25, fin=hoy)

La consulta con al=2026-07-18 devuelve 12; con al=2026-07-30, devuelve 15. El reclamo sigue en el grafo, consultable años después, y la cadena causal está a la vista: la rectificación está motivado_por el reclamo y rectifica la evaluación original. Si dentro de cinco años alguien revisa el caso de Lucía, el grafo le entrega la historia completa sin gimnasia alguna.

La trampa del UPDATE en las notas

Corregir una nota tienta a ejecutar UPDATE notas SET valor=15 WHERE id=…. Es la decisión que destruye la trazabilidad: al actualizar la celda, se borra la prueba de que alguna vez la nota fue 12 y de que un reclamo la cambió. El reflejo más natural del programador es, también aquí, el peor enemigo de la institución. El modelo lo previene: la nota anterior no se modifica, se le cierra el intervalo de vigencia y queda en el grafo.

Caso 6 · Una defensa de tesis con director y jurado

El último escenario es la defensa de tesis de Renata. Una tesis es una situación de larga duración (un año, en su caso) con varios participantes que no juegan el mismo papel:

La tesista es Renata, la agente principal. El director es el Dr. Acuña, un rol específico del dominio. Y el jurado lo componen tres personas con funciones distintas: la Decana Ortiz como presidenta, la Dra. Bravo como vocal y el Dr. Lima como secretario. En un sistema tradicional, todo esto pide una tabla tesis_participantes con una columna discriminadora de tipo, y cada consulta tiene que filtrar por ese código.

En WQuestions, cada rol es una tripleta separada. No hay tabla puente ni columna discriminadora: el rol es el nombre del cable. Preguntar «¿quién presidió el jurado de Renata?» es leer un solo enlace, jurado_presidente, sin filtrar ninguna columna de tipo. La forma del dato coincide con la forma de la pregunta.

tripletas
(tesis_renata,  agente,              renata_q)
(tesis_renata,  director_tesis,      dr_acuna)
(defensa_renata, parte_de,           tesis_renata)
(defensa_renata, jurado_presidente,  decana_ortiz)
(defensa_renata, jurado_vocal,       dra_bravo)
(defensa_renata, jurado_secretario,  dr_lima)
(defensa_renata, momento,            2026-12-04)

# la graduación: justificada por la defensa exitosa
(graduacion_renata, instancia_de,    graduar)
(graduacion_renata, agente,          renata_q)
(graduacion_renata, justificado_por, defensa_renata)

Roles como director_tesis, jurado_presidente, jurado_vocal y jurado_secretario no figuran en el catálogo canónico (ese catálogo invisible que vimos al hablar del lexicon). No importa: la política liberal del modelo los acepta sin protestar, y mientras el dominio universitario los use de forma consistente, el motor opera con ellos como si fueran canónicos. La graduación, por su parte, queda justificado_por la defensa: Renata se graduó porque defendió con éxito su tesis. El grafo deja la cadena causal escrita, sin un solo campo añadido al motor.

En una universidad, un expediente no es una foto del presente: es la película completa de una vida que el tiempo no debería poder reescribir.La lección del expediente académico

Del expediente al tablero del rectorado

Modelar la matrícula de Tomás y la malla que arrastra Aprendizaje de Máquina es resolver un caso. Pero el rectorado vive en el agregado: cuántos estudiantes siguen vigentes en cada carrera, qué curso acumula la tasa de desaprobación más alta, cuántos egresan dentro de los cinco años. Ninguna de esas preguntas pide una tabla nueva. La inscripción de cada alumno ya es una situación de tipo matricula con su carrera y su estado; la estadística del semestre es contar esas situaciones, agrupadas por la coordenada que el decano necesite.

python
# Matrículas vigentes en una carrera — un corte; el tablero recorre todas las carreras
count(u, Pattern(fixed={"carrera": u.ind("carrera_cc"), "estado": u.ind("vigente")},
                 type_constraint=u.ind("matricula")))

El antes y el después: del esquema fragmentado al grafo único

Pongamos las dos arquitecturas frente a frente con la pregunta que abrió el capítulo, ahora en su forma más exigente: ¿qué cadena de prerrequisitos arrastra «Aprendizaje de Máquina», cuáles de ellos ya aprobó Tomás y cuál le falta?

Antes, en el modelo relacional. La información se reparte entre alumnos, cursos, prerequisitos, matriculas y notas. Para expandir el árbol de dependencias de un curso hay que escribir un WITH RECURSIVE sobre prerequisitos, y luego cruzarlo con matriculas y notas mediante varios joins. Cada vez que la malla cambia (y cambia cada pocos años), la consulta hay que revisarla con lupa.

SQL
-- Antes: el árbol de prerrequisitos exige SQL recursivo.
WITH RECURSIVE cadena(curso) AS (
    SELECT prereq FROM prerequisitos WHERE curso = 'cc_420_aprendizaje'
  UNION
    SELECT p.prereq
    FROM prerequisitos p
    JOIN cadena c ON p.curso = c.curso
)
SELECT c.curso,
       CASE WHEN n.estado = 'aprobado' THEN 'ok' ELSE 'FALTA' END
FROM cadena c
LEFT JOIN notas n
       ON n.curso = c.curso AND n.alumno = 'tomas_q';
-- ...y todavía falta cruzar vigencias para la malla histórica.

Después, en WQuestions. La misma información vive como un solo grafo. Cada prerrequisito es una tripleta requiere_prereq; cada curso aprobado es un nodo alcanzable desde Tomás. La cadena completa de dependencias de Aprendizaje de Máquina se obtiene con un recorrido hacia atrás sobre las flechas requiere_prereq (sin SQL recursivo, sin procedimiento almacenado). Determinar qué le falta es restar dos conjuntos: la cadena de requisitos menos su subgrafo de aprobados. Y el grafo no distingue entre malla vigente y malla histórica: la bitemporalidad ya lo cubre, así que la misma consulta sirve para el plan de hoy y para el de hace diez años.

Qué quedó probado en este capítulo

La universidad es, probablemente, el dominio donde el timeline largo y los grafos de dependencia dejan de ser un detalle accesorio y se vuelven el problema central. El modelo absorbió ambas cosas con su maquinaria estándar, sin un solo añadido al motor:

El veredicto del dominio de la forma

  • Dependencias como grafo. La malla curricular es un DAG, y cada prerrequisito un hecho atómico. La pregunta «¿qué puedo tomar?» es un recorrido sobre el grafo que, de paso, devuelve lo que falta —no un sí o no mudo.
  • Historial intacto de por vida. La vigencia (D6) deja matrículas, notas y estados con su trayectoria completa durante toda la vida académica del egresado. La trampa del UPDATE nunca llega a ser una operación disponible.
  • Una persona, muchos roles. La agencia contextual (D5) permite que Renata sea estudiante, jefa de práctica y tesista a la vez: el grafo no distingue tipos de personas, sino tipos de situaciones.
  • Cadenas causales explícitas. El porqué repartido en cables (D7) deja a la vista que una rectificación se hizo por un reclamo, o que una graduación se justifica por una defensa. El audit trail es la topología misma del grafo.

Y, una vez más, el motor no creció ni una línea para absorber el dominio. Lo único que creció fue el lexicon: un puñado de verbos (matricular, dictar, evaluar, reclamar, rectificar_nota, graduar, defender_tesis) con sus signaturas, más un dialecto de dominio que mapea «estudiante», «docente», «tesista» o «director de tesis» a sus roles. En el próximo capítulo dejamos el campus y cruzamos a lo público: una municipalidad, donde las fechas de vigencia de una norma deciden la vida de un barrio entero.