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 pestañas abiertas. 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 lo rechaza con un mensaje seco: «No cumple prerrequisitos».

Pero Tomás está seguro de haber aprobado lo que hacía falta. ¿Le falta Estructuras de Datos, que pasó el ciclo pasado? ¿O es 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 está el problema que define a una universidad como dominio.

Una universidad no se parece a un comercio ni a un banco. Tiene dos rasgos propios.

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, el que da título al capítulo: las cosas dependen unas de otras. No puedes tomar Algoritmos sin haber pasado 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, cada una de estas preguntas pide algo distinto: una tabla histórica aquí, un WITH RECURSIVE allá, un procedimiento almacenado que copia en código la lógica del recorrido.

En WQuestions, cada una es un recorrido de uno o dos saltos sobre el mismo grafo. No hay una máquina distinta por 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), pone 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 serían seis listas inertes. Con ellos, una vida académica entera se vuelve un grafo navegable.

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?», la consulta es un 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 atributos (créditos, docente, aula, código, sílabo) sin que ninguno necesite 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 naturaleza un grafo dirigido acíclico, un DAG.

Las flechas tienen sentido, del requisito al 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 forma natural de toda dependencia ordenada: las tareas de un proyecto, las versiones de un documento, las migraciones de una base de datos, los prerrequisitos de una carrera.

Que no haya ciclos es 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 a la vez, uno de cada rama. 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. 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.

Ya podemos resolver el drama del lunes. «¿Qué cursos puede tomar Tomás este ciclo?» se vuelve un recorrido sobre el grafo.

Para cada curso, el motor mira sus flechas requiere_prereq y comprueba que todos los requisitos tengan, en el historial de Tomás, una evaluación aprobada. Si falta uno solo, el curso queda fuera.

Y esto es lo que el portal 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, los destinos de sus flechas requiere_prereq están todos dentro del conjunto de cursos que ese estudiante aprobó.

Es una operación de conjuntos sobre el grafo, sin join, sin SQL recursivo y sin procedimiento almacenado. Y la diferencia entre los dos conjuntos es 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 solo faltante: Cálculo. El portal podría haberle dicho «te falta Cálculo I para habilitar Algoritmos» en lugar de un «no» mudo.

El grafo conocía la respuesta desde el principio. Solo había que recorrerlo en vez 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 es poner una columna estado en la tabla de matrículas y actualizarla cuando alguien se retira.

El problema llega 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 dato 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. Así el grafo conserva gratis toda la trayectoria de la matrícula.

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)

«¿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, a la vez, 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 duele: una tabla estudiantes, otra docentes, claves cruzadas y un proceso de sincronización para el día en que un estudiante se vuelve 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 decide el verbo de la situación, no un «tipo» fijo de la persona. Renata es renata_q: agente en una matrícula (rol estudiante), agente en una asignación docente (rol jefa de práctica), agente en una tesis (rol tesista).

El sistema no distingue tipos de personas. Distingue tipos de situaciones. Cada rol vive en la suya.

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 las situaciones donde renata_q sea agente y proyecta su instancia_de. Sale una lista que abarca lo académico, lo docente y lo investigativo.

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 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 un ejercicio y presenta un reclamo formal el 20 de julio. La docente lo revisa, le da la razón y el 25 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 escrita.

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 causa se expresa con causado_por, motivado_por, con_finalidad y justificado_por.

La rectificación está motivado_por el reclamo, que fue su razón, y rectifica la evaluación original, que es su blanco. La graduación estará más adelante justificado_por la defensa. El rastro de auditoría no es una tabla aparte: es la forma misma 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, con su cadena a la vista. Si dentro de cinco años alguien revisa el caso de Lucía, el grafo le entrega la historia completa sin gimnasia.

La trampa del UPDATE en las notas

Corregir una nota tienta a ejecutar UPDATE notas SET valor=15 WHERE id=…. Esa decisión destruye la trazabilidad: al actualizar la celda se borra la prueba de que 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 propio del dominio. Y el jurado son tres personas con funciones distintas: la Decana Ortiz preside, la Dra. Bravo es vocal, el Dr. Lima secretario.

En un sistema tradicional, todo esto pide una tabla tesis_participantes con una columna 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 de tipo: el rol es el nombre del cable.

Preguntar «¿quién presidió el jurado de Renata?» es leer un solo enlace, jurado_presidente. 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 están en el catálogo canónico. No importa: el modelo los acepta sin protestar, y mientras la universidad 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 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 con varios joins. Cada vez que la malla cambia, y cambia cada pocos años, hay que revisar la consulta 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 sale de un recorrido hacia atrás sobre las flechas requiere_prereq, sin SQL recursivo y sin procedimiento almacenado. Saber qué le falta es restar dos conjuntos.

Y el grafo no distingue entre malla vigente y malla histórica: los dos tiempos ya lo cubren. 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 el dominio donde el tiempo largo y los grafos de dependencia dejan de ser un detalle y se vuelven el problema central. El modelo absorbió los dos con su maquinaria de siempre, 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 otra vez, el motor no creció ni una línea. Lo único que creció fue el lexicon: unos verbos (matricular, dictar, evaluar, reclamar, rectificar_nota, graduar, defender_tesis) con sus firmas, más un dialecto que traduce «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.