---
name: compactacion-contexto
description: Anti-context-rot. Detectar cuándo compactar el contexto, guardar estado antes de compactar, técnicas de resumen progresivo y handoff limpio entre contextos. Recalibrado para el tokenizer de Opus 4.7 (+15-30% tokens vs 4.6).
version: "1.1.0"
herramientasPermitidas: [Read]
exclusiones:
  - "No cargar si el contexto está por debajo del 50% y no hay señales cualitativas de degradación — compactar sin necesidad solo interrumpe el flujo."
  - "No cargar para compactar archivos grandes de código fuente; los archivos se leen bajo demanda con Read, no se mantienen en contexto activo."
  - "No cargar en medio de una tarea atómica que aún no terminó — la compactación debe ocurrir en puntos de completitud, no a mitad de una implementación."
  - "No cargar para gestionar el presupuesto del context-builder entre sesiones; para eso usar `context-builder`."
evolvable: true  # default para skill estandar
---
# Compactación de Contexto

## El problema: context-rot

Un contexto largo y sin estructura se degrada con el tiempo:
- Las instrucciones tempranas quedan enterradas y se olvidan.
- El modelo pierde el hilo de qué se hizo y qué falta.
- Las respuestas se vuelven repetitivas o contradictorias.
- El rendimiento cae porque el contexto útil se diluye en tokens de ruido.

**Context-rot** es el fenómeno donde un contexto largo produce peores resultados que
uno compacto y fresco con el estado correcto cargado.

---

## Señales de que es hora de compactar

### Señales cuantitativas
- La ventana de contexto está al **50% o más** de su límite.
  (Umbral bajado desde 60% por el tokenizer de Opus 4.7, que produce 1.0–1.35×
  más tokens para el mismo contenido que Opus 4.6. El contexto útil se llena
  antes aunque la conversación tenga el mismo tamaño aparente.)
- La conversación lleva más de **30 turnos** sobre el mismo proyecto.
  (Bajado desde 40 por la misma razón — el volumen efectivo por turno es mayor.)
- Se han cargado más de 5 archivos grandes sin eliminar contexto anterior.

### Señales cualitativas
- El agente empieza a repetir preguntas ya respondidas.
- El agente olvida decisiones tomadas hace 10+ turnos.
- Las respuestas son más genéricas y menos específicas al proyecto.
- El agente contradice algo que él mismo propuso anteriormente.
- La latencia de respuesta aumenta notablemente.

---

## Protocolo: guardar estado ANTES de compactar

Antes de iniciar cualquier compactación, el agente DEBE persistir el estado en archivos.
El estado en la memoria del contexto desaparece; el estado en disco persiste.

### Archivo ESTADO.md — estado de ejecución

```markdown
# ESTADO.md — Estado del proyecto al 2026-03-25T14:32:00

## Fase actual
- Fase: 3 — Implementación de módulo de reportes
- Sprint: 2 de 3
- Última tarea completada: Endpoint GET /reportes/{id}
- Próxima tarea: Endpoint POST /reportes (slice 3.2)

## Decisiones arquitectónicas tomadas
- Se usa PostgreSQL con JSONB para metadatos de reportes (no MongoDB).
- Autenticación via JWT con refresh tokens, no sesiones.
- El frontend es Angular standalone, sin NgModules.
- Paginación por cursor, no por offset.

## Archivos modificados en esta sesión
- backend/app/routers/reportes.py (creado)
- backend/app/schemas/reporte.py (creado)
- backend/app/models/reporte.py (modificado: campo metadata JSONB)
- frontend/src/app/reportes/reportes.component.ts (creado)

## Problemas conocidos / deuda técnica
- El endpoint DELETE /reportes/{id} falta validación de permisos (ticket #47)
- La migración 003_reportes.py necesita revisión manual antes de producción

## Tests en estado rojo
- test_reporte_exportar_pdf → falta dependencia wkhtmltopdf en CI

## Contexto del negocio relevante
- Los reportes son propiedad del usuario que los crea (no del admin).
- Los reportes tienen un TTL de 30 días, luego se archivan.
```

### Archivo DECISIONS.md — registro de decisiones

```markdown
# DECISIONS.md

## 2026-03-25 — Paginación por cursor
**Contexto**: El endpoint GET /reportes necesitaba paginación.
**Opciones evaluadas**: offset/limit, cursor, keyset.
**Decisión**: Cursor basado en (created_at, id) para estabilidad con datos en tiempo real.
**Consecuencia**: Los clientes no pueden saltar a página N directamente.

## 2026-03-24 — JSONB para metadatos
**Contexto**: Los reportes tienen atributos variables por tipo.
**Decisión**: Un campo `metadata JSONB` en lugar de tabla EAV.
**Consecuencia**: Queries de metadatos requieren índices GIN.
```

---

## Técnicas de resumen progresivo

### Técnica 1: Resumen en capas

No resumir todo en un solo párrafo plano. Usar capas de detalle:

```
Nivel 0 (1 línea): "Construyendo API REST de reportes con FastAPI + PostgreSQL."
Nivel 1 (5 líneas): qué fases hay, en cuál estamos, cuál es el siguiente paso.
Nivel 2 (20 líneas): decisiones clave, archivos importantes, problemas abiertos.
Nivel 3 (archivo completo): ESTADO.md detallado.
```

Cargar el nivel de detalle apropiado según la tarea a realizar.

### Técnica 2: Resumen por dominios

Separar el contexto en dominios independientes:

```markdown
## Dominio: Backend API
- Rutas implementadas: GET/POST/DELETE /reportes
- Pendiente: PUT /reportes/{id}, webhooks

## Dominio: Frontend Angular
- Componentes: ReportesListComponent, ReporteDetalleComponent
- Pendiente: ReporteCrearComponent, filtros de búsqueda

## Dominio: Base de datos
- Migraciones aplicadas: 001, 002, 003
- Pendiente: índice GIN en metadata (pendiente de medir impacto)
```

### Técnica 3: El "snapshot de trabajo"

Antes de compactar, crear un mensaje de handoff en lenguaje natural que un nuevo
contexto pueda leer y continuar sin perder información:

```
Proyecto: Sistema de reportes SIGAF
Estoy implementando el módulo de reportes. Completé los endpoints de lectura
(GET /reportes y GET /reportes/{id}) con paginación por cursor y RBAC.

El siguiente paso ES implementar POST /reportes. El schema ReporteCreate ya está
en backend/app/schemas/reporte.py. El modelo ORM está en backend/app/models/reporte.py.
El servicio parcial está en backend/app/services/reporte_service.py (falta el método crear).

Importante: los reportes deben asociarse al usuario del JWT, nunca confiar en el
body del request para el owner_id.
```

---

## Protocolo de handoff entre contextos

### El contexto saliente (antes de compactar)

1. Escribir ESTADO.md actualizado con toda la información relevante.
2. Hacer commit de todos los cambios pendientes.
3. Anotar el hash del último commit en ESTADO.md.
4. Escribir el "snapshot de trabajo" como primer mensaje del nuevo contexto.

### El contexto entrante (después de compactar)

Protocolo de arranque:

```
1. Leer ESTADO.md para entender el estado actual.
2. Leer DECISIONS.md para entender las decisiones ya tomadas.
3. Revisar los últimos 3 commits para entender qué se hizo recientemente.
4. Hacer git status para ver si hay cambios sin commitear.
5. Leer ÚNICAMENTE los archivos relevantes para la tarea actual.
```

Nunca cargar todo el codebase en el nuevo contexto. Cargar solo lo necesario para
la tarea inmediata.

---

## Estrategias de compactación activa

### Compactación por completitud de tarea

Compactar al terminar cada tarea atómica. Una tarea completada = contexto que ya
no necesita vivir en memoria activa.

### Compactación por fase del proyecto

Al pasar de una fase a otra (ej. del diseño a la implementación), compactar toda
la discusión de diseño y cargar solo las decisiones finales.

### Compactación de archivos grandes

Si se leyó un archivo de 500 líneas para extraer 3 funciones relevantes, compactar
el archivo completo y mantener solo los 3 fragmentos extraídos con sus firmas.

---

## Verificación post-compactación

Toda compactación DEBE verificar que no destruyó información crítica. Antes de
descartar el contexto original, validar estas invariantes:

| Invariante | Verificación | Tolerancia |
|------------|-------------|------------|
| **Headings** | Contar `#` en original y compactado — deben coincidir exactamente | 0% — cada heading perdido es una sección desaparecida |
| **Bloques de código** | Contar delimitadores ``` — deben coincidir en pares | 0% — código perdido es irrecuperable |
| **Rutas de archivo** | Extraer paths (`src/`, `app/`, extensiones `.py`, `.ts`, etc.) — comparar sets | 0% — una ruta perdida rompe la navegabilidad |
| **URLs** | Extraer `http://` y `https://` — comparar sets | 0% — referencias externas irrecuperables |
| **Items de lista** | Contar bullets (`-`, `*`, numerados) en secciones críticas | ±15% — la compactación puede fusionar items redundantes |
| **Decisiones/ADRs** | Verificar que toda decisión del original aparece en el compactado | 0% — decisiones perdidas se re-debaten |

**Protocolo de validación**:

1. Extraer invariantes del contexto original ANTES de compactar
2. Compactar el contexto
3. Extraer las mismas invariantes del resultado
4. Comparar — si alguna invariante de tolerancia 0% falla, la compactación se rechaza
5. Si los items de lista exceden ±15%, revisar manualmente qué se fusionó

Si la compactación falla la validación: no descartar el original. Recompactar con
instrucción más conservadora o compactar por secciones individuales.

---

## Gotchas / Errores comunes no obvios

- **Compactar sin escribir ESTADO.md primero**: el agente ejecuta `/compact` con la información del estado solo en el contexto de la conversación. Tras la compactación, el estado desaparece y la sesión siguiente parte de cero. Causa: se confundió la compactación del contexto con el guardado de estado. Solución: escribir ESTADO.md (y DECISIONS.md si corresponde) en disco ANTES de compactar — el protocolo lo establece en el primer paso.
- **Invariante de headings violada silenciosamente**: el contexto compactado pierde dos secciones `##` del original porque el modelo resumió párrafos en lugar de preservar la estructura. Causa: no se ejecutó la validación post-compactación. Solución: antes de descartar el contexto original, contar `#` en ambos con regex y comparar — tolerancia 0% para headings perdidos.
- **Compactar todo el codebase al inicio de sesión**: el agente lee 20 archivos en el nuevo contexto "para orientarse" y los compacta de inmediato. Causa: se interpretó "cargar contexto fresco" como cargar y compactar todo. Solución: en el contexto entrante, cargar ESTADO.md + DECISIONS.md + 3 últimos commits, y solo los archivos de la tarea inmediata — no más.
- **Umbral de 70% sin recalibrar para Opus 4.7**: en proyectos que migraron de Opus 4.6 a 4.7, el umbral de compactación sigue configurado al 70% del contexto cuando debe ser 50%. Causa: el tokenizer de 4.7 produce 1.0-1.35× más tokens y el umbral efectivo llega antes. Solución: al actualizar modelo, ajustar el umbral de compactación a 50% como documenta este skill en su sección de señales cuantitativas.

## Anti-patrones a evitar

- **Compactar sin guardar estado**: El estado debe estar en disco ANTES de compactar.
- **Cargar todo el codebase al nuevo contexto**: Cargar solo lo necesario para la tarea.
- **Hacer el handoff en lenguaje ambiguo**: El snapshot debe ser preciso y accionable.
- **No registrar decisiones tomadas**: Las decisiones no escritas se pierden al compactar.
- **Compactar en medio de una tarea**: Terminar la unidad atómica de trabajo primero.
- **Depender de la memoria del contexto para información crítica**: Todo lo crítico va a disco.
- **Compactar sin verificar invariantes**: Validar headings, código, rutas y URLs post-compactación.
