# Rubrica Builder

> Crea, cura y audita rúbricas de evaluación autosuficientes para Active-IA a partir de la consigna de cualquier entrega (TP, parcial, recuperatorio, final o global). En modo CURAR analiza la consigna ANTES de armar la rúbrica y detecta requisitos que rompen el flujo de corrección de la IA (links de repo, videos, imágenes en un TP de código, "el deploy anda", informe PDF + código juntos), proponiendo para cada uno adaptarlo a un solo flujo —código O PDF—, dejarlo para corrección manual o sacarlo de la rúbrica, y reescribe la consigna curada sin perder la intención. En modo CREAR genera el JSON de criterios listo para el botón "Cargar criterios"; en modo AUDITAR recibe consigna + rúbrica existente y la corrige detectando contradicciones, omisiones e invenciones, reajustando pesos a 100. En modo TEST simula la corrección real (consolidación + prompt del workflow N8N→Gemini) localmente con el CLI de Claude, para ver qué nota y feedback produce la rúbrica sobre una entrega antes de subirla. Usá esta skill SIEMPRE q

- Skill: `juancruzrobledo/rubrica-builder` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add juancruzrobledo/rubrica-builder`
- Raw SKILL.md: https://api.skillmd.com/api/skills/juancruzrobledo/rubrica-builder/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: juancruzrobledo (https://skillmd.com/u/juancruzrobledo)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/juancruzrobledo/rubrica-builder

---


# Rúbrica Builder — crear y auditar rúbricas autosuficientes

Construís el instrumento con el que después se corrige. La meta no es una rúbrica
"linda": es una rúbrica **autosuficiente**. ¿Por qué importa tanto? Porque cuando
el sistema corrige, la IA ve SOLO dos cosas: **la rúbrica y la entrega del alumno**.
Nunca vuelve a mirar la consigna. Si un requisito del TP no quedó escrito en la
rúbrica, sencillamente NO se evalúa. La rúbrica es el único puente entre lo que el
profesor pidió y lo que la IA corrige.

Por eso toda la skill gira alrededor de una sola pregunta: **¿se puede corregir
esta entrega con esta rúbrica, sin tener la consigna a mano?** Si la respuesta es
no, la rúbrica está incompleta.

## El principio que decide la granularidad (leé esto siempre)

Esta skill genera rúbricas **v2** por defecto: el puntaje ya no vive solo en el
**criterio** (`peso`) — el **subcriterio también tiene `peso` propio**, y la suma de
los pesos de los subcriterios de un criterio debe dar exactamente el `peso` de ese
criterio (ver `references/modelo-rubrica.md`). Sigue existiendo el modelo viejo, v1
(subcriterios sin `peso`, puro checklist), para rúbricas ya cargadas — pero lo que
generás vos, siempre que puedas, es v2.

Como el subcriterio ahora también puntúa, la vieja regla ("si necesita descontarse
solo, promovelo a criterio") ya no es la palanca correcta: un subcriterio con `peso`
propio YA es una palanca de descuento independiente. La pregunta que decide la
granularidad pasa a ser otra:

> **¿Es un área/dimensión distinta de evaluación (ortogonal a las demás)? → criterio
> propio. ¿Es un requisito específico y granular DENTRO del área que ya cubre un
> criterio? → subcriterio con su propio `peso`, aunque merezca descontarse solo.**

**El test de granularidad** — para cada requisito evaluable, preguntate:
- *¿Es una dimensión/área de evaluación distinta de las demás (otro aspecto del
  trabajo, no un detalle de uno ya existente)?* → **criterio propio con `peso`**.
- *¿Es un requisito puntual dentro del área que ya cubre un criterio, aunque merezca
  su propio descuento?* → **subcriterio con `peso` propio** (v2) o evidencia (v1).

Caso típico: en un TP con "Endpoints CRUD" como área/criterio, cada operación
(POST, GET, PUT, DELETE) NO es un área distinta — es un requisito específico dentro
de esa área → subcriterio con `peso`, no criterio nuevo. En cambio "Persistencia en
base de datos" sí es un área ortogonal a "Endpoints CRUD" → criterio propio.

**Pero no sobre-fragmentes.** Más criterios no es mejor por default: partir cosas
triviales en muchos criterios de 1–2 puntos diluye la resolución de peso y vuelve la
rúbrica ruidosa. El corte es por *área real que la consigna distingue* — no por
prurito de separar, y no por "esto necesita su propio descuento" (eso ya lo resuelve
el `peso` del subcriterio en v2).

**Refuerzo numérico:** cuando un criterio agrupa varios subcriterios, usá
`instrucciones_puntuacion` como nota complementaria no vinculante (ej: "penalizar
doble si falta manejo de errores") — el reparto de puntaje entre subcriterios ya lo
dice el `peso` de cada uno, no hace falta describirlo en texto.

## Antes de empezar: leé el modelo

Leé `references/modelo-rubrica.md`. Es la fuente de verdad del esquema (replica el
Pydantic real) y documenta **ambas versiones**: v1 (subcriterios sin `peso`, para
rúbricas ya cargadas) y v2 (subcriterios con `peso` propio, la que esta skill genera
por defecto). Ahí también está documentado `modo_consolidacion` /
`extensiones_personalizadas`: gracias al JSON portable de Active-IA, este campo ya
viaja DENTRO del JSON que se pega en "Cargar criterios" (opcional — si no viene, no
pasa nada, el form no lo toca). Esta skill los completa siempre que pueda: una
rúbrica no es autosuficiente si el corrector ni siquiera va a leer el archivo donde
vive la evidencia. Y si vas a curar una consigna (o crear una rúbrica), leé también
`references/limites-corrector.md`: documenta qué puede y qué NO puede evaluar el
corrector (links, imágenes, ejecución, un solo flujo código/PDF), espejo del servicio
real de consolidación. Tené presente las trampas del repo:
- `docs/specs/Rubrica.md` usa `nota_final` → **mal**, es `nota_maxima`.
- la skill vieja `skills/rubricas/` usa `puntaje_maximo` por criterio y no tiene
  subcriterios → **modelo muerto y distinto tanto de v1 como de v2, ignorala**.
- el peso del criterio es `peso` (no `puntaje_maximo`), y la suma debe dar 100.
- `schema_version` NO va dentro del JSON de criterios: es un campo aparte del
  formulario. Lo que marca una rúbrica como v2 es la presencia de `peso` en los
  subcriterios — nunca escribas `schema_version` en el JSON (ver "Formato de
  salida").

## Inputs que necesitás

| Modo | Necesitás |
|------|-----------|
| **CURAR** | La **consigna** completa + (opcional) el **formato de entrega** real (código o PDF). |
| **CREAR** | La **consigna** completa de la entrega (texto, PDF, imágenes, tablas). |
| **AUDITAR** | La **consigna** + la **rúbrica existente** (JSON) a revisar. |
| **TEST** | La **rúbrica** (JSON) + una **entrega** de alumno (archivo, carpeta, .zip o .txt). |

Si falta la consigna, no inventes: pedila. Sin consigna no hay forma de saber qué
debe evaluar la rúbrica, y una rúbrica adivinada es exactamente el problema que
esta skill viene a resolver.

Si la consigna trae **imágenes, tablas, diagramas o esquemas** relevantes para la
evaluación, traducilos a texto dentro de la rúbrica (en la `descripcion` del
criterio o en las `evidencias`). La IA correctora no va a ver esa imagen — solo lee
la rúbrica. Lo que no esté en texto, no existe.

## Detectar el modo

- Consigna + pedido de **revisar si se puede corregir / curar / adaptar la
  consigna** ("¿esto lo corrige la IA?", "curá este TP", "pide una foto y es de
  código") → **CURAR**.
- Solo consigna, pedido de **armar la rúbrica/criterios** → **CREAR**.
- Consigna + un JSON de rúbrica → **AUDITAR**.
- Rúbrica + una entrega de alumno (probar/testear) → **TEST**.
- Ante la duda, preguntá cuál de los cuatro quiere.

CURAR es el paso de aguas arriba: corre sobre la consigna ANTES de CREAR. Si al
crear una rúbrica detectás un requisito que rompe el flujo de corrección (ver
"Modo CURAR"), no escribas el criterio fantasma en silencio: frená y curá ese
punto primero.

---

## Modo CURAR — adaptar la consigna al flujo de corrección

Antes de armar la rúbrica, una pregunta que nadie suele hacerse: **¿esta consigna se
puede corregir con la IA tal como está?** Porque el corrector tiene límites duros
(leé `references/limites-corrector.md`): no abre links, descarta imágenes en modos de
código, corrige **un solo flujo —código O PDF—** y no ejecuta nada. Si la consigna le
pide algo de eso, por más fiel que sea la rúbrica, ese punto no se corrige. CURAR
detecta esos puntos y los resuelve **sin perder la intención del trabajo**.

La meta NO es mutilar la consigna. Es **mantener un solo flujo de corrección** y, donde
se pueda, adaptar el requisito para que entre en ese flujo conservando el objetivo
pedagógico. Lo que no se puede adaptar no se borra: se mantiene y se marca para
corrección manual.

### Distinción clave: consigna ≠ rúbrica

- **La consigna NUNCA pierde algo importante.** Se adapta o se mantiene tal cual.
- **La rúbrica es la que no incluye lo incorregible.** "Sacar" aplica SOLO a la
  rúbrica: lo que la IA no puede evaluar no se escribe como criterio. La consigna lo
  conserva igual.

### Los tres destinos de un punto que rompe el flujo

1. **ADAPTAR (preferido).** Reescribí el requisito para que viva dentro del flujo único
   y siga siendo IA-corregible, conservando la intención. Ejemplos:
   - *"Entregá el link del repositorio"* → *"Entregá un `.zip` del proyecto y que el
     `README` incluya la URL del repo, para chequear que se subió."*
   - *"Adjuntá una imagen de la salida del programa"* → *"Imprimí esa salida por
     pantalla / dejá el output en un `.txt` dentro del proyecto."*
   - *"Mostrá el diagrama de la arquitectura"* → *"Describí la arquitectura en el
     `README` o en comentarios del código."*
   - *"El deploy tiene que estar online"* → *"Incluí el código del deploy y un
     `README` con los pasos; la evidencia se verifica sobre el código."*

2. **MANTENER + CORRECCIÓN MANUAL.** Si el punto es importante pero NO se puede adaptar
   sin romper el flujo (caso típico: un **video** de defensa), se queda **igual en la
   consigna** —no se cura— y el informe lo marca: *"esto la IA no lo corrige; queda en
   la consigna, se corrige a mano, NO entra en la rúbrica."* (El video de defensa, de
   hecho, tiene su propio canal: la skill `active-ia-video-feedback`.)

3. **SACAR (solo de la rúbrica).** Si es accesorio para la nota (un link decorativo, un
   zip de entrega), simplemente no se escribe como criterio. La consigna lo mantiene.

### El flujo es conversacional

CURAR no decide solo los casos que importan. Trabajá así:

1. **Detectá** todos los puntos de la consigna que rompen el flujo (cotejá contra
   `references/limites-corrector.md`). Anclá cada uno en una cita de la consigna.
2. **Decidí el flujo primario** —código o PDF— según lo que la consigna pide. Si la
   consigna mezcla código + informe PDF y no está claro, **preguntá** cuál es el canal.
3. **Para cada punto, proponé una cura con recomendación concreta y preguntá** qué
   hacer. Ejemplo:
   > *"El formato de entrega pide un link y eso rompe el flujo. Yo recomendaría pedir
   > un `.zip` y que el `README` muestre el repo, así se chequea que se subió. ¿Lo
   > adaptamos así, lo dejás para corrección manual, o lo sacamos?"*
4. **Aplicá lo que el usuario decida** y pasá al siguiente punto.
5. **Entregá** el informe de curado + la consigna reescrita (ver formato abajo).

Si no hay nada que rompe el flujo, decilo: la consigna es corregible tal cual, no hace
falta curar. No inventes problemas.

### Formato de salida de CURAR

**1. Informe de curado** — por cada punto detectado:
```
## Curado de la consigna

Flujo de corrección recomendado: <código (solo_codigo / web_completo / proyecto_completo) | PDF>

- [<ADAPTADO | MANUAL | SACADO-DE-RÚBRICA>] <qué pide la consigna, citado>
  - Por qué rompe el flujo: <límite estructural concreto>
  - Cura aplicada: <qué se hizo y, si adaptado, cómo quedó el texto>
- ... (un ítem por punto)

Veredicto: <corregible tal cual | corregible con estos ajustes | requiere corrección
manual de algunos puntos>
```

**2. Consigna reescrita** — el texto curado completo, en un bloque, fiel a la intención
original, con los puntos ADAPTADOS ya reexpresados y los MANUALES marcados como "se
corrige a mano". Listo para pasárselo a **CREAR**.

Cuando el usuario quiera, encadená con **CREAR** sobre la consigna ya curada: así la
rúbrica que sale es 100% corregible en un solo flujo.

---

## Modo CREAR

Objetivo: traducir la consigna en una rúbrica completa y autosuficiente.

1. **Leé la consigna entera y extraé requisitos.** Listá TODO lo evaluable:
   funcionalidades pedidas, restricciones técnicas (lenguaje, framework, versiones),
   condiciones de entrega (repo público, formato, deadline si afecta nota),
   validaciones exigidas, estructura obligatoria, lo que está prohibido. Cada
   requisito explícito del TP tiene que terminar reflejado en algún criterio o
   evidencia. Anclá todo en el texto: si no está en la consigna, no entra.

2. **Agrupá en criterios según la granularidad de descuento, no un número fijo.**
   Cada criterio es una **palanca de nota independiente** (ver "El principio que
   decide la granularidad"). Aplicá el test a cada requisito: lo que el profesor
   quiera poder penalizar por separado va como criterio propio; lo que es
   verificación interna de algo más grande va como subcriterio. Como referencia
   suele haber entre 4 y 12 criterios, pero el número lo dicta la cantidad de
   palancas reales, no una cuota. Asigná `peso` según la importancia que la consigna
   le da — más peso a lo troncal. La suma debe dar **exactamente 100**.

3. **Bajá cada criterio a subcriterios con evidencias y `peso` propio (v2).** Las
   evidencias son el corazón de la corrección: afirmaciones binarias, verificables
   mirando SOLO la entrega. "Existe la ruta `POST /productos`" es buena evidencia;
   "el código está bien escrito" no lo es (subjetiva, no verificable). Cada
   subcriterio necesita ≥1 evidencia. Además, asignále un `peso` a cada subcriterio
   de forma que la suma cierre **exacto** con el `peso` del criterio padre:
   - Si la consigna o la importancia relativa de cada subcriterio te da una
     ponderación clara, usala.
   - Si no hay ponderación clara, repartí en partes iguales con el **método del
     resto mayor (Hamilton)**: `base = floor(peso_criterio / n)`,
     `resto = peso_criterio - base * n`; los primeros `resto` subcriterios (en
     orden) reciben `base + 1`, el resto recibe `base`. Ejemplo: criterio de
     `peso: 25` con 3 subcriterios → `base=8`, `resto=1` → `9, 8, 8` (suma 25).

4. **Determiná el `modo_consolidacion`** (y, si hace falta, `extensiones_personalizadas`).
   Con los criterios y evidencias ya armados, releé QUÉ archivos necesita **leer** el
   corrector para verificar cada evidencia (ver `references/limites-corrector.md`,
   tabla de extensiones por modo) y elegí:
   - Todo lo evaluable vive en código fuente puro, sin HTML/CSS ni README que haga
     falta leer → **`solo_codigo`**.
   - Proyecto web (HTML/CSS/JSON de config) → **`web_completo`**.
   - Además hay que leer README/Markdown, YAML, SQL, scripts de shell,
     `.properties`, `.gradle`, etc. (documentación de ejecución, migraciones,
     configuración) → **`proyecto_completo`**.
   - La consigna pide algo con una extensión que ningún modo predefinido cubre
     (notebooks `.ipynb`, `.r`, `.dart`, datasets `.csv`, etc.) → **`personalizado`**,
     listando en `extensiones_personalizadas` EXACTAMENTE las extensiones que hacen
     falta (con el punto, ej: `.ipynb`).
   - **Chequeo cruzado obligatorio:** recorré cada evidencia que ya escribiste y
     confirmá que el archivo donde vive está cubierto por el modo elegido. Una
     evidencia sobre un archivo que el modo no va a leer es tan inútil como un
     requisito omitido — el corrector directamente no lo ve (filtro de extensión,
     ver `references/limites-corrector.md`).

5. **Penalizaciones y condiciones de desaprobación.** Si la consigna establece
   castigos (repo privado, no compila) o reglas que tumban la nota (plagio, falta un
   requisito troncal), modelalas. `penalizaciones` descuentan un %; las
   `condiciones_desaprobacion` ponen un techo (`nota_maxima`). Si la consigna no dice
   nada de esto, dejalos como `[]` — no inventes castigos que el profesor no pidió.

6. **Validá** con el script (ver "Validación obligatoria").

7. **Entregá** en el formato de salida de abajo.

---

## Modo AUDITAR

Acá sos un profesor experto en evaluación haciendo análisis crítico. Tenés la
consigna y un borrador de rúbrica. Tu trabajo es dejar la rúbrica fiel, estricta y
completa respecto del TP, y autosuficiente para corregir. Revisá en este orden:

### Paso 0 — Migración v1→v2 (si la rúbrica es vieja)

Antes de auditar contenido, chequeá el modelo: **si ningún subcriterio trae
`peso`, la rúbrica es v1 y la migrás a v2 como parte de esta misma auditoría.**
No es opcional y no hace falta preguntar — la mejor rúbrica es siempre la v2.
Regla dura de la migración: **no se pierde información**. Todo criterio,
subcriterio, descripción y evidencia existente se conserva; lo único que
cambia es cómo queda organizado. La migración toca SOLO `criterios` y
`subcriterios`: `titulo`, `descripcion` de la rúbrica, `metadata`,
`penalizaciones` y `condiciones_desaprobacion` quedan exactamente igual que
en la v1 original (si hay que tocarlos, es por otro paso de la auditoría —
Contradicciones, Omisiones, etc. —, no por la migración en sí).

**Por qué no alcanza con solo agregar `peso`:** en v1, si un profesor quería
poder descontar el POST, el GET y el PUT/DELETE de un CRUD por separado, no
tenía otra opción que hacer un criterio por cada uno — el subcriterio no
puntuaba. Es común encontrar así 2 o más criterios v1 que en realidad son
**la misma área partida en varios** solo por esa limitación técnica. Migrar
bien significa detectar esos grupos y volver a fusionarlos en un solo
criterio v2 con subcriterios — no solo pegarle un `peso` a lo que ya había.

**a) Agrupá los criterios existentes por área real.** Para cada criterio,
   preguntate si forma grupo con otro(s) usando el mismo test de "El principio
   que decide la granularidad" (¿área distinta, o instancia de la misma área?).
   Señales de que un grupo de criterios **se fusiona**:
   - Nombres en patrón paralelo que solo cambian el objeto: "Endpoint POST",
     "Endpoint GET", "Endpoint PUT/DELETE"; "Crear relación Alumno", "Crear
     relación Curso".
   - La consigna los presenta como ítems de **una misma instrucción
     enumerada** ("el CRUD debe soportar: crear, leer, actualizar, eliminar"),
     no como puntos distintos del trabajo.
   - Fallar uno no es un tipo de error distinto que fallar otro — es el mismo
     chequeo aplicado a instancias distintas.

   Señal de que **NO** se fusionan (quedan como criterios propios): si
   armaras un índice de la rúbrica, cada uno merecería su propio renglón
   porque evalúan cosas de naturaleza distinta (ej: "Persistencia" vs.
   "Documentación" vs. "Seguridad").

**b) Para cada grupo de 2+ criterios que se fusiona**, construí un único
   criterio v2:
   - `peso` del nuevo criterio = **SUMA de los `peso` de los criterios
     fusionados** (no se pierde ni un punto).
   - `nombre`/`descripcion` = el área común, sintetizando los nombres
     originales.
   - Cada criterio original pasa a ser **UN subcriterio** del nuevo:
     - `peso` del subcriterio = el `peso` que tenía ESE criterio, **heredado
       tal cual** (por eso acá no hace falta Hamilton — la ponderación ya
       existía, solo se baja un nivel; 15+15+15=45=peso del nuevo criterio,
       automático).
     - `descripcion` = la descripción del criterio original.
     - `evidencias` = todas las evidencias de todos los subcriterios v1 que
       tenía ese criterio, **copiadas literal** (no las reformules ni las
       resumas — son afirmaciones verificables, cambiarles la letra puede
       cambiar qué verifican), aplanadas en una sola lista, sumando la
       descripción de cada uno de esos subcriterios v1 como evidencia si
       aporta información nueva.
     - `instrucciones_puntuacion` que tuviera el criterio original se sube al
       `instrucciones_puntuacion` del nuevo criterio (campo válido solo a
       nivel criterio), indicando a qué subcriterio corresponde cada regla.

   Ejemplo: `C2: Endpoint POST (peso 15)`, `C3: Endpoint GET (peso 15)`,
   `C4: Endpoint PUT/DELETE (peso 15)` → un solo `C2: Endpoints CRUD (peso
   45)` con subcriterios `C2.1` (peso 15, era C2), `C2.2` (peso 15, era C3),
   `C2.3` (peso 15, era C4).

**c) Para los criterios que quedan solos** (no forman grupo — ya eran su
   propia área): si tienen varios subcriterios v1 sin peso, ahí sí repartí
   con **Hamilton** (o la ponderación de la consigna si es clara), porque acá
   no hay un peso previo del que heredar — es la primera vez que ese
   requisito se pondera por partes.

**d) Recalculá Σ `peso` de los criterios == 100.** Como cada fusión conserva
   el total (suma de pesos fusionados), esto normalmente ya cierra solo; si
   no cierra, hay un error en alguna fusión.

**e) (Opcional, prolijidad)** Renumerá los `id` de criterio para que queden
   correlativos sin huecos tras las fusiones — no lo exige el validador, pero
   ayuda a leer la rúbrica.

**f) Verificá completitud antes de seguir.** Este paso es obligatorio, no
   opcional — es lo que sostiene la regla de "no se pierde información".
   Recorré la rúbrica v1 original elemento por elemento (cada criterio, cada
   subcriterio, cada evidencia, cada `instrucciones_puntuacion`) y confirmá
   que cada uno aparece en algún lugar del resultado v2: como criterio, como
   subcriterio, o como evidencia. Si conscientemente decidís no llevar algo
   (por ejemplo porque el paso 4, Invenciones, lo identifica como algo que la
   consigna no respalda), NO lo saques en silencio durante la migración —
   dejalo como estaba en el Paso 0 y sacalo recién en el paso correspondiente
   de la auditoría, para que quede reportado con su motivo.

**g) Reportá la migración en el resumen de hallazgos** (ver "Formato de
   salida"): la tabla de mapeo `criterio/subcriterio v1 → dónde quedó en v2`
   (qué se fusionó, en qué área nueva y con qué peso; qué quedó igual), y la
   confirmación de que el chequeo de completitud del punto (f) no encontró
   nada faltante.

Con la rúbrica ya en v2 (recién migrada, o porque ya lo era), seguí con los
pasos de auditoría de contenido de abajo.

1. **Contradicciones.** Puntos donde la rúbrica choca con la consigna. Ejemplo
   clásico: el TP exige eliminar/no usar algo y la rúbrica lo da por opcional o
   premia dejarlo. Corregí para que la rúbrica diga lo mismo que el TP.

2. **Omisiones.** Requisitos explícitos e importantes del TP que la rúbrica no
   evalúa: condiciones de entrega, validaciones específicas, restricciones técnicas,
   estructura obligatoria, ejecución. Agregalos como criterios, subcriterios o
   evidencias. Esta es la falla más grave: lo omitido nunca se corrige.

3. **Requisitos diluidos.** Para cuando llegás acá la rúbrica ya está en v2 (Paso
   0 la migró si hacía falta), así que la dilución real ya no es "subcriterio
   sin peso propio" (eso el modelo lo resuelve solo): es otra cosa. Revisá:
   - **Área mal ubicada:** un requisito que es una dimensión de evaluación
     distinta (ver "El principio que decide la granularidad") está enterrado
     como subcriterio de un criterio que no le corresponde → promovelo a
     criterio propio y reajustá pesos.
   - **Peso de subcriterio mal repartido:** un subcriterio importante quedó con
     un `peso` chico dentro de un criterio grande, sin reflejar su peso real en
     la consigna (ej: repartiste en partes iguales cuando la consigna pondera
     distinto) → reajustá los pesos entre subcriterios (deben seguir sumando el
     `peso` del criterio).
   - **Remanente sin desglosar:** un criterio grande con un solo subcriterio que
     absorbe todo el `peso` cuando en realidad agrupa varios requisitos
     independientes que convendría desglosar en más subcriterios con `peso`
     propio, para que el corrector tenga granularidad real al puntuar.

4. **Invenciones.** Criterios, concesiones o reglas que la rúbrica trae pero el TP
   no respalda en ningún lado. Sacalos. La rúbrica no puede ser más blanda ni más
   exigente que la consigna; debe ser su espejo fiel. (Ojo el doble filo: tampoco
   metas evidencias que el corrector NO puede verificar mirando solo la entrega —ej:
   "entregó el video", "el repo es público"—; alucina. Si no es verificable en el
   material que recibe, no va como evidencia puntuable.)

5. **Elementos visuales.** Si el TP tiene imágenes/tablas/esquemas que importan para
   evaluar y la rúbrica no los refleja en texto, incorporalos.

6. **Modo de consolidación.** Fijate qué `modo_consolidacion` trae la rúbrica (si no
   trae ninguno, el backend asume `solo_codigo`) y confirmá que cubre las
   extensiones de TODOS los archivos que las evidencias necesitan leer (tabla en
   `references/limites-corrector.md`). Si encontrás una evidencia que depende de un
   archivo cuya extensión el modo actual no cubre — caso típico: pide revisar el
   `README.md` pero el modo es `solo_codigo`, que no incluye `.md` — es una omisión
   estructural tan grave como un criterio faltante: el corrector jamás va a leer ese
   archivo, por más bien redactada que esté la evidencia. Subí el modo
   (`web_completo`/`proyecto_completo`) o pasá a `personalizado` con las extensiones
   exactas, y dejalo reportado en los hallazgos.

7. **Ajuste de pesos.** Si agregaste, sacaste o consolidaste criterios (incluida la
   migración del Paso 0), recalculá los `peso` para que la suma vuelva a ser
   exactamente 100, y que la de los subcriterios de cada criterio cierre con su
   `peso`. Respetá la importancia relativa que da la consigna.

8. **Validá** con el script.

9. **Entregá** con el formato de salida (incluyendo el resumen de hallazgos).

---

## Modo TEST — simular la corrección

Una rúbrica válida no garantiza una rúbrica que corrija BIEN. El modo TEST cierra
ese hueco: corre una corrección real sobre una entrega concreta y te muestra nota +
feedback, para que veas si la rúbrica discrimina lo que tiene que discriminar antes
de subirla.

Replica el pipeline del sistema (consolidación del código + prompt de corrección),
pero dispara la corrección con el CLI de Claude en vez de N8N→Gemini. Claude actúa
como reemplazo del modelo de producción; los resultados son indicativos (otro
modelo), no idénticos al puntaje final que dará Gemini, pero sirven para detectar
problemas de la rúbrica.

```bash
python scripts/simular_correccion.py \
  --rubrica <rubrica.json> \
  --entrega <archivo|carpeta|.zip|.txt> \
  --materia "Nombre de la materia" \
  --alumno  "Nombre del alumno" \
  --modo solo_codigo            # o web_completo | proyecto_completo | personalizado
```

- `--modo` es **opcional** si el JSON de la rúbrica ya trae `modo_consolidacion` (lo
  que ahora genera CREAR/AUDITAR): el script lo toma de ahí solo. Pasalo a mano solo
  para forzar un modo distinto al que trae la rúbrica.
- `--no-run` arma el material y te imprime el comando, sin ejecutar claude (útil para
  inspeccionar el `prompt_correccion.txt` que recibirá el modelo).
- `--tipo TP` si la rúbrica es un `CriteriosStructure` sin campo `tipo`.
- `--ext ".ipynb,.sql"` para `--modo personalizado` (o dejá que lo tome de
  `extensiones_personalizadas` si ya está en el JSON).
- Guarda `prompt_correccion.txt` (material exacto) y `correccion.json` (resultado).

**Cómo leer el resultado.** El script valida la corrección contra la rúbrica y avisa
si: un criterio no fue evaluado, un puntaje supera su peso, la suma no cierra, o se
aplicó una penalización/condición inexistente. Pero lo importante es tu juicio:
¿la nota refleja la calidad real de la entrega?, ¿el feedback cita evidencias
concretas?, ¿algún criterio quedó ambiguo y el modelo dudó? Si algo no cierra, suele
ser la rúbrica la que hay que mejorar (descripciones vagas, evidencias no
verificables, pesos mal repartidos) — volvé a CREAR/AUDITAR y re-testeá.

### Qué consume el corrector (importante para diseñar la rúbrica)

La corrección usa la rúbrica **COMPLETA**: por cada criterio manda `id`, `nombre`,
`peso`, `descripcion`, `instrucciones_puntuacion` y **subcriterios con sus
evidencias**, más las `penalizaciones`, las `condiciones_desaprobacion` y la
`metadata`. Por eso las evidencias importan: son el checklist que el modelo verifica.

En **v2**, además manda el `peso` de cada subcriterio, y el resultado de la
corrección trae un desglose `subcriterios_evaluados` por criterio (puntaje,
estado y feedback por subcriterio, cuya suma debe dar el `puntaje_obtenido` del
criterio). En **v1** no hay `peso` de subcriterio ni `subcriterios_evaluados` en
la respuesta — sigue igual que siempre. `scripts/simular_correccion.py` infiere
la versión igual que hace el validador (por presencia de `peso` en subcriterios)
y ajusta el prompt y la validación del resultado en consecuencia.

Recomendación de robustez: redactá la `descripcion` de cada criterio de forma
autosuficiente —que resuma lo que sus evidencias verifican—, así la corrección
funciona bien aun si una integración llegara a enviar menos contexto del esperado.

---

## Validación obligatoria

Antes de entregar cualquier rúbrica, guardá el JSON y corré:

```bash
python scripts/validar_rubrica.py <ruta_al_json>
```

(o `python scripts/validar_rubrica.py -` para leerlo por stdin)

El script replica las reglas del backend real: si pasa, el sistema acepta la
rúbrica; si falla, te dice exactamente qué corregir (suma de pesos, IDs, patrones,
evidencias vacías, `nota_final` vs `nota_maxima`, etc.). **No entregues una rúbrica
sin que el validador la dé por buena.** Si falla, arreglá y volvé a correrlo. Es
barato y te ahorra el rebote del backend.

El validador soporta **v1 y v2** e infiere cuál es por presencia de `peso` en los
subcriterios (igual que el frontend de Active-IA) — no hace falta pasarle
`schema_version`. En v2 exige `peso` en cada subcriterio y que la suma cierre exacto
con el `peso` del criterio; en v1 no lo exige. Si necesitás forzar la versión (por
ejemplo para probar el comportamiento v1 explícitamente), usá
`--schema-version 1|2`.

## Formato de salida

ALWAYS entregá en este orden:

**1. (Solo en AUDITAR) Resumen de hallazgos** — breve, antes del JSON:
```
## Hallazgos
- Migración v1→v2: <"la rúbrica ya era v2, sin cambios" | mapeo
  "criterio/subcriterio v1 → dónde quedó en v2" con cada fusión y su peso
  heredado | "no aplica">
- Verificación de completitud: <"OK, todo el contenido v1 está presente en
  el v2" | qué faltaba y se agregó>
- Contradicciones: <qué y dónde, o "ninguna">
- Omisiones: <qué requisitos faltaban, o "ninguna">
- Invenciones: <qué se quitó, o "ninguna">
- Modo de consolidación: <"OK, cubre todas las evidencias" | qué extensión faltaba
  cubrir y a qué modo se subió>
- Ajuste de pesos: <cómo quedó el reparto>
```

**2. El JSON de `CriteriosStructure`** — en un bloque ```json, listo para pegar en
el botón "Cargar criterios" (o en el modal de edición: ambos ya soportan el JSON
portable de Active-IA). Contiene: `titulo`, `descripcion`, `puntaje_maximo`,
`metadata`, `criterios`, `penalizaciones`, `condiciones_desaprobacion`, y **siempre**
`modo_consolidacion` — más `extensiones_personalizadas` si `modo_consolidacion` es
`"personalizado"` (si no lo es, omitilo o dejalo en `null`). Este es el campo que
antes se perdía al copiar/pegar el JSON: ahora viaja con la rúbrica y el formulario
lo autocompleta solo. **No incluyas `schema_version`**: es un campo aparte del
payload de la rúbrica (como `tipo`/`numero`/`anio`), no de `CriteriosStructure`. Lo
que marca la rúbrica como v2 es el `peso` en cada subcriterio — el front de
Active-IA lo infiere solo.

**3. Campos para el formulario** — identidad de la instancia, no del contenido; NO
van en el JSON y se tipean aparte:
```
Para completar en el formulario de la rúbrica:
- tipo: <TP | PARCIAL_1 | ... según la consigna>
- numero: <ej: 2 para el TP2>
- anio: <año académico>
(materia_id lo elegís vos según la materia)
```

**4. Confirmación del validador** — pegá la línea de "✅ RÚBRICA VÁLIDA".

Mirá `assets/ejemplo-rubrica.json` como molde de una rúbrica v2 completa y válida
(con `peso` por subcriterio y `modo_consolidacion` correctamente elegido — en ese
ejemplo, `proyecto_completo`, porque uno de sus criterios evalúa el `README.md` y
`solo_codigo`/`web_completo` no incluyen `.md`). Para retrocompatibilidad,
`examples/rubrica-tp-cli-v1.json` es un ejemplo v1 (sin `peso` en subcriterios).

## Errores que arruinan una rúbrica (evitalos)

- Pesos que no suman 100 — el error más común; el validador lo caza, pero pensalo
  desde el reparto.
- Evidencias subjetivas o que piden info fuera de la entrega ("está prolijo").
- Inventar penalizaciones/condiciones que la consigna no menciona.
- Dejar requisitos del TP sin ningún criterio que los cubra.
- **Requisitos importantes diluidos**: un área/dimensión de evaluación distinta
  enterrada como subcriterio de un criterio que no le corresponde, en vez de
  criterio propio (ver "El principio que decide la granularidad").
- **(v2) Subcriterios sin `peso` o cuya suma no cierra** con el `peso` del
  criterio padre — el validador lo caza, pero pensalo desde el reparto (Hamilton
  si no hay ponderación clara en la consigna).
- **Sobre-fragmentar** lo trivial en muchos criterios de 1–2 puntos: diluye la
  resolución de peso y vuelve la rúbrica ruidosa. Partí por palanca real, no por
  prurito.
- Usar `nota_final` en vez de `nota_maxima`, o `puntaje_maximo` por criterio en vez
  de `peso` (eso es el modelo V1 muerto).
- Meter `materia_id`/`tipo`/`numero`/`anio` dentro del JSON de criterios: van en el
  formulario, no en el JSON que se importa.
- **Elegir un `modo_consolidacion` que no cubre las extensiones que tus propias
  evidencias necesitan** (ej: evidencia sobre el `README.md` con modo `solo_codigo`,
  que no incluye `.md`) — la evidencia queda de adorno: el corrector nunca va a leer
  ese archivo. Hacé siempre el chequeo cruzado del paso 4 de CREAR / paso 6 de
  AUDITAR.

