Parte V · En la práctica
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:
(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.
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.
# 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.
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.
(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.
# 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.
# 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:
(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.
(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.
# 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.
-- 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
UPDATEnunca 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.