---
name: swl:release
description: Gestión del ciclo de release del proyecto. Genera versión siguiendo SemVer, crea changelog automático desde commits con Conventional Commits, valida que los tests pasan, crea tag de git y genera release notes. Flags: --tipo=patch|minor|major, --dry-run, --skip-tests.
allowed_tools: ["Read", "Write", "Edit", "Bash", "Glob", "Grep"]
evolved: true
evolved-from: "5.10.5"
evolved-at: "2026-04-20"
evolved-by: "aprender"
evolved-note: "Paso 10 integra scripts/verificar-release.js como gate anti-gap obligatoria tras 3 releases consecutivos donde el release-manager-swl omitio archivos"
---

# /swl:release — Gestión del ciclo de release

Eres el gestor de releases del proyecto. Orquestas el proceso completo de crear una nueva versión: calcular el número de versión, recopilar cambios, validar estado publicable y crear artefactos de release.

**Carga**: `Skill("release-semver")` — contiene las reglas de SemVer, Conventional Commits, estrategia de tags y proceso detallado de release. Delega toda lógica de versionado al skill.

## Cuándo usar este comando

- Al completar un conjunto de features o fixes listos para producción
- Al final de un sprint cuando hay cambios acumulados
- Para hotfixes críticos (patch release)
- Antes de una demo o entrega a cliente

## Flags soportados

```
--tipo=patch     Incrementa PATCH (0.0.X) — bugs y correcciones menores
--tipo=minor     Incrementa MINOR (0.X.0) — features nuevas sin breaking changes
--tipo=major     Incrementa MAJOR (X.0.0) — breaking changes
--dry-run        Muestra qué haría sin ejecutar nada
--skip-tests     Omite tests. Requiere justificación y confirmación explícita.
```

Si no se pasa `--tipo`, se determina automáticamente según los commits (ver skill).

## Paso 0 — Verificación de prerrequisitos

```bash
git rev-parse --is-inside-work-tree 2>&1
git branch --show-current
git status --porcelain
git remote -v
```

- Si hay cambios sin commitear, DETENER y listar archivos pendientes.
- Si la rama no es la principal, advertir y pedir confirmación.

## Paso 1 — Leer versión actual

```bash
cat package.json 2>/dev/null | grep '"version"' | head -1
cat pyproject.toml 2>/dev/null | grep "^version" | head -1
cat VERSION 2>/dev/null
git describe --tags --abbrev=0 2>/dev/null || echo "Sin tags previos"
```

Si hay múltiples fuentes, pedir al usuario que confirme la canónica. Sin versión en ningún lugar: `0.0.0`.

## Paso 2 — Recopilar y clasificar commits

```bash
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null)
if [ -z "$LAST_TAG" ]; then
  git log --oneline --format="%H %s"
else
  git log --oneline --format="%H %s" ${LAST_TAG}..HEAD
fi
```

Clasifica cada commit según Conventional Commits (tipos y su impacto en versión definidos en `Skill("release-semver")`).

## Paso 3 — Calcular tipo de versión

Si no se especificó `--tipo`, usar reglas del skill:
- Breaking change en algún commit -> MAJOR
- feat: sin breaking changes -> MINOR
- Cualquier otro caso -> PATCH

Si el usuario pasó `--tipo` y hay discrepancia (ej: breaking changes con --tipo=patch), advertir y pedir confirmación.

## Paso 4 — Calcular nueva versión

Aplica reglas SemVer del skill: MAJOR resets MINOR y PATCH a 0, MINOR resets PATCH a 0.

Si `--dry-run`, mostrar preview del changelog y terminar sin modificar nada.

## Paso 5 — Ejecutar tests

Si NO se pasó `--skip-tests`, detectar runner y ejecutar:

```bash
ls package.json pytest.ini setup.cfg pyproject.toml Makefile 2>/dev/null
npm test 2>&1 || pytest 2>&1 || make test 2>&1
```

Si fallan, DETENER. Si `--skip-tests`, pedir confirmación explícita ("confirmo").

## Paso 6 — Actualizar archivos de versión

Actualiza la versión en TODOS los archivos que la contienen. Para proyectos SWL-SES, la checklist obligatoria es:

```
[ ] package.json
[ ] package-lock.json (2 ubicaciones: líneas 3 y 9)
[ ] plugin.json
[ ] CLAUDE.md
[ ] README.md
[ ] AGENTS.md
[ ] COMANDOS.md
[ ] MANUAL_USO.md
[ ] INSTALACION.md
[ ] SALUD.md
[ ] INVENTARIO.md
[ ] CHANGELOG.md (entrada nueva)
[ ] .planning/COMPACTACION.md
[ ] .planning/ESTADO.md
[ ] .swl-install-state.json (si existe)
```

Para proyectos no-SWL: actualiza los archivos detectados en Paso 1 (package.json, pyproject.toml, VERSION).

### Tres capas de versionado — NO confundir

El sistema SWL versiona en tres capas independientes. El bump de versión del SISTEMA toca SOLO la capa 1:

| Capa | Qué versiona | Cuándo cambia | Tocar en `/swl:release`? |
|------|--------------|---------------|--------------------------|
| **1. Sistema** | El paquete `@saulwade/swl-ses` como conjunto | En cada release | **SÍ — los 15 archivos del checklist arriba** |
| **2. Componente individual** | Frontmatter `version:` de cada agente o skill (`agentes/*.md`, `habilidades/*/SKILL.md`) | Cuando el componente específico cambia (ver `/swl:aprender` Paso 6 acción 2) | **NO — cada componente versiona independiente** |
| **3. Histórico** | Referencias a versiones pasadas en `CHANGELOG.md`, `CHANGELOG-LEGACY.md`, ADRs, RELEASE-NOTES, comentarios `Histórico: hasta vX.Y...` | Nunca (son inmutables por definición) | **NO — son registros históricos** |

Verificación post-bump con `grep -rn "<versión-anterior>"` revelará decenas o cientos de matches en capas 2 y 3 — eso es esperado y correcto. Filtrar ruido para confirmar que las únicas líneas modificadas son de la capa 1:

```bash
# Después del bump, validar consistencia SOLO en archivos canónicos del sistema
node -e "
const p=require('./package.json'),l=require('./plugin.json');
const lock=require('./package-lock.json');
const ok = p.version===l.version && l.version===lock.version;
console.log(ok ? 'OK consistente: '+p.version : 'INCONSISTENTE');
"
```

Si el chequeo del nodo arriba dice OK pero `grep` aún muestra matches de la versión anterior, esos matches son **capa 2 (frontmatter)** o **capa 3 (histórico)** y son legítimos — no tocarlos.

### Republish-only entre registries (caso especial)

Si el publish dual falla en uno de los 2 registries (typically npmjs o GitHub
Packages) pero el otro queda publicado, **NO se puede reintentar la misma versión**
— ningún registry permite sobreescribir versiones. Ejecutar inmediatamente un bump
PATCH (1.X.Y → 1.X.(Y+1)) siguiendo el checklist arriba, y publicar solo al
registry faltante con `node scripts/publicar.js --solo-npmjs` o `--solo-github`.

Documentar el republish exclusivamente como "republish de coordinación entre
registries" en CHANGELOG, sin atribuirle cambios funcionales que no existen.

Ver `Skill("release-semver")` sección "Publish a múltiples registries" para detalles.

## Paso 6.5 — Regenerar skills-lock.json

Antes del CHANGELOG, regenerar el lock de skills para capturar el estado de
los 151 SKILL.md de la release:

```bash
node scripts/generar-skills-lock.js
git add manifiestos/skills-lock.json
```

El lock contiene SHA256 de cada SKILL.md y permite que `/swl:salud` detecte
drift silencioso entre releases. Si el lock no cambió respecto al anterior,
el commit lo refleja como no-op (idempotente). El archivo es pequeño (~37KB)
y debe versionarse.

## Paso 7 — Generar CHANGELOG

Desde v1.6.5 este paso usa el skill `changelog-generator` para parsear
Conventional Commits y producir el bloque listo para insertar (ADR-0029).

### Paso 7.1 — Cargar skill y previsualizar

```
Skill("changelog-generator")
```

Ejecutar el parser determinista contra los commits del rango actual:

```bash
node habilidades/changelog-generator/scripts/parse-commits.js \
  --from <tag-anterior> --to HEAD --version <nueva-version> --format markdown
```

El script imprime el bloque markdown listo para insertar Y reporta a stderr
el ratio de conformidad Conventional Commits. Categorías generadas en orden
canónico: Breaking changes → Nuevas funcionalidades → Correcciones →
Mejoras de rendimiento → Cambios internos → Reversiones → Evoluciones de
skills/agentes → Mantenimiento → Otros.

### Paso 7.2 — Gate de conformidad

Verificar la conformidad (impresa a stderr o vía `--format json`):

- **>= 80% conformidad**: continuar a 7.3.
- **< 80% conformidad**: detenerse y reportar al usuario los commits caídos
  bajo "Otros". Pedir decisión:
  1. Continuar con el bloque generado (los "Otros" quedan al final del CHANGELOG).
  2. Abortar release y reescribir commits no conformes (`git rebase -i`).
  3. Editar manualmente la sección "Otros" antes de insertar.

NO continuar automáticamente con conformidad baja — el changelog público
queda confuso.

### Paso 7.3 — Insertar en CHANGELOG.md

Leer `CHANGELOG.md` actual:
- Si no existe: crear con header `# Changelog\n\n` y luego el bloque nuevo.
- Si existe: insertar el bloque nuevo inmediatamente después del header
  `# Changelog` (antes de la entrada anterior).

Escritura atómica obligatoria (regla CLAUDE.md). Usar `atomicWriteSync` desde
`hooks/lib/atomic-write.js` cuando se llame programáticamente.

### Paso 7.4 — Verificar entrada generada

```bash
head -40 CHANGELOG.md
```

Confirmar:
- Header `## [<nueva-version>] - YYYY-MM-DD` presente.
- Categorías generadas tienen contenido coherente con los commits del rango.
- Breaking changes (si los hay) aparecen al inicio.

### Fallback manual (legacy v1.6.4 y anterior)

Si el parser falla o el skill no está disponible, mantener el flujo manual
de versiones previas:
- Secciones: Funcionalidades nuevas, Correcciones, Mejoras de rendimiento,
  Cambios internos, Breaking Changes, Estadísticas.
- Descripciones legibles por humanos (sin prefijo feat:/fix:).
- Omitir commits style: y test: del changelog público.

## Paso 8 — Commit de release y tag

```bash
git add package.json pyproject.toml setup.py VERSION CHANGELOG.md 2>/dev/null
git commit -m "chore(release): versión [nueva-versión]"
git tag -a "v[nueva-versión]" -m "Release v[nueva-versión]"
```

Usar tags anotados siempre (regla del skill).

## Paso 9 — Generar RELEASE-NOTES

Crea `RELEASE-NOTES-v[nueva-versión].md` con: resumen, cambios, instrucciones de actualización y guía de migración si hay breaking changes.

## Paso 10 — Verificación final

### 10.1 Gate automática anti-gap (OBLIGATORIA antes del push)

Ejecutar `scripts/verificar-release.js` que valida que la versión nueva esté reflejada en las 14 ubicaciones canónicas de la checklist (y avisa sobre MANUAL_USO opcional):

```bash
node scripts/verificar-release.js
```

Exit codes:
- `0` — todas las ubicaciones obligatorias con la versión correcta, puedes continuar al push
- `1` — al menos un archivo quedó en versión anterior. **NO hacer push hasta corregir**. El reporte indica el archivo y el problema específico
- `2` — error de invocación (package.json ausente, versión inválida)

Ejemplo de output en éxito:
```
[OK] package.json: version=5.10.5
[OK] plugin.json: version=5.10.5
[OK] package-lock.json: version=5.10.5, packages[""].version=5.10.5
...
[OK] CHANGELOG.md: seccion [5.10.5] presente con fecha
Resultado: 14/15 OK, 1 WARN opcional(es)
```

Ejemplo de output en fallo que obliga a corregir:
```
[FALLA] .planning/MAPEO_SKILLS_AGENTES.md: solo 0 ocurrencia(s) de 5.10.5 (minimo 1)
[FALLA] README.md: primera linea no menciona 5.10.5 — actual: "# swl-software-engineering-system v5.10.4"
Resultado: 13/15 OK, 2 FALLA(S) obligatoria(s)
```

Esta gate existe porque el agente `release-manager-swl` ha omitido archivos en 3 releases consecutivos (5.10.3, 5.10.4, 5.10.5 — ver APRENDIZAJES.md) pese a tener la checklist documentada en su frontmatter. Un checklist textual no basta: se necesita ejecución.

### 10.1.1 Gate de cobertura por lenguaje (regeneración obligatoria)

Tras el verificar-release.js, regenerar la matriz lenguaje × cobertura SWL:

```bash
node scripts/generar-matriz-lenguajes.js
```

El script reescribe `.planning/cobertura-lenguajes.md` con el estado actual.
Comparar contra el commit anterior:

```bash
git diff .planning/cobertura-lenguajes.md
```

Si algún lenguaje **bajó de status** (completo → parcial, parcial → faltante)
sin ADR documentado en `.planning/adrs/` justificando la regresión, **NO hacer
release**. La regresión silenciosa de cobertura erosiona la promesa "polyglot"
del repo.

Si el cambio es esperado (eliminación deliberada de un componente), el ADR
debe existir con número y fecha y referenciarse en el commit del release.

Lo mismo aplica para releases con incremento de cobertura: la nueva matriz se
commitea junto al release y se menciona en RELEASE-NOTES.

### 10.2 Verificación manual post-gate

```bash
git tag -l "v[nueva-versión]"
git log --oneline -3
head -30 CHANGELOG.md
```

## Paso 11 — Reporte final

```
=== Release v[nueva-versión] completado ===

Versión anterior: v[versión-anterior]
Nueva versión:    v[nueva-versión]
Tipo:             [PATCH | MINOR | MAJOR]

Archivos actualizados: [lista]
Git: Commit [hash], Tag v[nueva-versión]
Commits incluidos: [N] (feat: [N], fix: [N], otros: [N])
Tests: [ejecutados OK | omitidos (--skip-tests)]

Próximos pasos:
  1. Revisar RELEASE-NOTES-v[nueva-versión].md
  2. git push origin v[nueva-versión]
  3. Publicar release en GitHub/GitLab si aplica
  4. Notificar al equipo
```

## Reglas de comportamiento

- NUNCA crear release con repositorio dirty.
- NUNCA omitir actualización de archivos de versión — inconsistencias causan errores de build.
- NUNCA usar `--skip-tests` sin documentarlo en CHANGELOG y sin confirmación.
- Si tipo calculado es MAJOR pero usuario pidió --tipo=patch, reportar discrepancia y esperar confirmación.
- CHANGELOG legible por alguien que no conoce el código.
- Si es monorepo, reportar que no se soporta y sugerir lerna/changesets.
