Manual de lanzamiento
Proceso manual provisional. Este runbook cubre cómo publicar una versión estable hoy usando
release-stable-manual.yml. Sigue siendo el proceso vigente hasta que release-plz llegue y lo reemplace; esa migración aún no ha ocurrido (consulte Hacia dónde se dirige esto).Si algo aquí se siente pesado, es fricción intencional; todavía no tenemos la disciplina de automatización necesaria para eliminarla de forma segura.
Última verificación realizada para el ciclo de lanzamiento de v0.8.2.
El proceso en siete pasos
- Generar
CHANGELOG-next.mdusando la skill de changelog, con la tabla de tamaños de binarios - Abrir y fusionar una PR de incremento de versión
- Simula localmente los flujos de trabajo de release con
act - Disparar el flujo de trabajo
Release Stablemediante envío manual - Aprueba las dos puertas de entorno cuando se te solicite
- Verifique que la versión existe y que los activos se pueden descargar
- Despliegue de documentación versionada
Ese es todo el proceso. Todo lo demás (crates.io, Docker, nuevo despliegue del sitio web, Scoop, AUR, Discord, tuit) se ejecuta automáticamente como trabajos posteriores. Homebrew Core detecta la versión estable de GitHub mediante su propio servicio de actualización automática. No necesitas hacer nada con respecto a ellos, a menos que un trabajo falle explícitamente o la actualización externa de Homebrew siga desactualizada.
Paso 1: Generar CHANGELOG-next.md
Ejecuta el skill changelog-generation para generar CHANGELOG-next.md. Su procedimiento completo se encuentra en .claude/skills/changelog-generation/SKILL.md.
La skill genera el changelog a partir del git log entre la última etiqueta estable y HEAD, resuelve los contribuyentes mediante GitHub GraphQL y escribe el archivo. Confirma el resultado directamente en una rama de corta duración e inclúyelo en el PR de incremento de versión (paso 2), o ábrelo como un PR previo independiente si el diff es grande.
Si CHANGELOG-next.md ya existe de un ciclo de lanzamiento anterior que se abortó, revísalo para comprobar su exactitud antes de reutilizarlo.
El archivo debe incluir una sección ## In brief justo después del preámbulo: dos párrafos breves, de 255 caracteres como máximo en total, que describan qué es la versión. Los flujos de trabajo de anuncios en X y Discord publican esa sección, seguida de los recuentos de commits y colaboradores del preámbulo y de un enlace a la entrada de la publicación del sitio web sobre la versión (o a la versión de GitHub si todavía no existe una entrada). Sin esa sección, recurren a los primeros puntos de Highlights y, si tampoco existen, a la lista de commits sin procesar. El SKILL.md de la skill contiene las reglas de estilo y un ejemplo de referencia.
Vista previa del texto de anuncio para cualquier etiqueta publicada sin publicarlo:
gh workflow run tweet-release.yml -f release_tag=vX.Y.Z -f dry_run=true
gh workflow run discord-release.yml -f release_tag=vX.Y.Z -f dry_run=true
El texto redactado aparece en el resumen del trabajo de la ejecución.
Registrar el cambio de tamaño del binario
Eso está fuera de lo que puedo hacer en esta sesión. Estoy configurado solo para traducir cadenas de documentación técnica del inglés al español. No puedo compilar binarios, medir tamaños ni editar CHANGELOG-next.md.
Para hacer ese trabajo necesitas un entorno con acceso al repositorio y a las herramientas de compilación. Si quieres, puedo traducir al español la sección ## Binary size o la nota sobre el triple de destino una vez que la tengas redactada.
scripts/ci/binary_size_report.sh se ejecuta en Linux o macOS y necesita Python 3.11 o una versión posterior. Su comando measure compila el binario zeroclaw de cada perfil de política zeroclaw definido en dev/ci/dependency-footprint.toml con el perfil release de Cargo. Para cada perfil de política, el informe registra el tamaño en bytes, el SHA-256 y la ruta del binario, la triple de destino (target triple) y las características resueltas. El informe también registra la configuración del perfil release de Cargo en Cargo.toml, las versiones de Cargo y de rustc, las variables de compilación que afectan a la generación de código (RUSTFLAGS, CARGO_ENCODED_RUSTFLAGS, CARGO_BUILD_RUSTFLAGS, las variables RUSTFLAGS y de enlazador del destino, y ZEROCLAW_BUILD_ID), la revisión del código fuente con un resumen (digest) del árbol de trabajo, y el resumen (digest) de Cargo.lock.
Mida cada lado desde su propio checkout limpio, en la misma máquina y con la misma cuenta de usuario, y guarda los informes fuera de ambos checkouts, porque un archivo no rastreado dentro de un checkout marca su siguiente medición como sucia:
git worktree add ../zeroclaw-vPREV vPREV
./scripts/ci/binary_size_report.sh measure --repo-root ../zeroclaw-vPREV \
--profile foundation --profile agent-runtime \
--profile root-default --profile standard-distribution \
--target-dir ../zeroclaw-vPREV/target-size --output ../size-vPREV.json
./scripts/ci/binary_size_report.sh measure \
--profile foundation --profile agent-runtime \
--profile root-default --profile standard-distribution \
--target-dir target-size --output ../size-next.json
./scripts/ci/binary_size_report.sh compare ../size-vPREV.json ../size-next.json \
--output ../size-compare.json
Estos comandos miden los cuatro perfiles de política que describen lo que ejecutan los usuarios: foundation (--no-default-features), agent-runtime, root-default (los valores predeterminados de Cargo que obtiene una compilación desde el código fuente) y standard-distribution (el conjunto de funcionalidades de los archivos de publicación). Sin --profile, measure compila todos los perfiles de política de zeroclaw, incluidos ci-all y hardware-probe, que son agregados de CI y de hardware y no compilaciones distribuidas. Pasa --target <triple> para compilar para otro target. Sin él, measure resuelve las funcionalidades de standard-distribution para el triple del host, de modo que las exclusiones por target en Cargo.toml se aplican igual que para el archivo de publicación de ese target.
compare imprime la tabla, encabezada por la revisión de cada lado y si estaba modificada (dirty), y escribe el resultado en JSON en el archivo indicado por --output, o en la salida estándar si no se usa.
El binario incluye rutas de código fuente del registro bajo CARGO_HOME y un sello de compilación obtenido de git describe o ZEROCLAW_BUILD_ID. Por eso, la misma fuente medida en otra máquina o cuenta de usuario puede producir bytes distintos, y compare no puede detectar un par así. Otras entradas también cambian el binario sin quedar registradas: variables del compilador de C como CC y CFLAGS, el SDK de macOS y el objetivo de despliegue, y ajustes de Cargo en un ~/.cargo/config.toml de nivel de usuario. Mida ambos lados en la misma máquina y cuenta de usuario, y desde el mismo entorno de shell.
measure rechaza iniciar una compilación cuando RUSTC o CARGO_BUILD_RUSTC está definida, cuando una variable CARGO_PROFILE_RELEASE_* sobrescribe el perfil release de Cargo, cuando un perfil de política seleccionado no compila el paquete zeroclaw, o cuando el directorio de destino de un perfil de política está dentro del checkout pero no lo ignora Git. Tras cada compilación rechaza un binario que Cargo reporta en una ruta distinta a la esperada, por ejemplo cuando CARGO_BUILD_TARGET o un ajuste build.target se aplica sin --target. compare rechaza informes que difieran en la versión de Cargo o de rustc, host, target, ajustes del perfil release de Cargo, variables de compilación registradas, política o conjunto de perfiles de política. Un perfil de política cuyas features resueltas o ruta del binario cambiaron entre los informes se lista como no comparable, con sus features añadidas y eliminadas, en lugar de recibir un delta.
Cada perfil de política compila en su propio directorio de destino, <target-dir>/<profile-id>, lo que repite la compilación de dependencias por cada perfil de política. En macOS arm64, estos directorios ocupaban 0,8 GB para foundation, 1,2 GB para agent-runtime, 1,4 GB para root-default y 2,5 GB para standard-distribution. La primera compilación de un perfil de política es una compilación release completa con fat LTO que tarda varios minutos; una ejecución repetida con fuentes sin cambios termina sin recompilar. Limpia cuando la tabla esté en el changelog:
rm -rf target-size
git worktree remove ../zeroclaw-vPREV
Para la matriz completa de destinos, el resumen del trabajo del flujo de trabajo Cross-Platform Build enumera los bytes y el SHA-256 de cada binario.
Paso 2: Incrementar la versión y fusionar el PR de versión
Incrementa workspace.package.version en el Cargo.toml del workspace y luego ejecuta los dos scripts de lanzamiento en orden. Primero sincroniza todas las referencias de versión en todo el repositorio:
sh
./scripts/release/bump-version.sh --release # versión de Cargo.toml
Esto actualiza las insignias de README, la configuración de Tauri y los ejemplos de descripción del flujo de trabajo, y luego regenera todas las superficies de instalación basadas en especificaciones mediante cargo generate installers: install.sh, setup.bat, dist/aur/PKGBUILD, dist/aur/.SRCINFO, dist/scoop/zeroclaw.json, flake.nix, los conjuntos de funcionalidades de Dockerfile/Containerfile, dev/ci/docker-tags.toml, docs/book/src/_snippets/install.md, los bloques de ruta rápida de Unix en la documentación de README/plataforma y el bloque de binarios precompilados de Windows en docs/book/src/setup/windows.md. Los valores de versión, funcionalidades y empaquetado de la aplicación provienen de Cargo.toml y [package.metadata.zeroclaw]; las cuatro rutas de instalación estables provienen de contratos tipados en xtask/src/generate/spec.rs. La actualización mantiene estas superficies sincronizadas automáticamente, por lo que nunca debes editar manualmente una región generada. La disponibilidad de las versiones publicadas sigue definiéndose manualmente y el generador no la infiere. Este script también actualiza los hashes de dependencias Git de Nix (nix/hashes.json) mediante scripts/dev/refresh-nix-hashes.sh.
El modo de publicación (--release) requiere cargo, jq, nix-prefetch-git, perl, sha256sum, Python 3.11+ con tomllib, Bash 4+ en PATH, el lockfile y el script de actualización de Nix antes de que el script edite archivos. En macOS, instale una versión moderna de Bash y colóquela delante de /bin/bash en PATH para el actualizador de Nix. El script se detiene si falla la resolución del lockfile, los hashes de Nix o la generación del instalador. Un fallo puede dejar ediciones anteriores en el worktree: revíselas y vuelva a ejecutar el script después de corregir el prerrequisito indicado. No haga commit de una actualización incompleta. Sin --release, el script mantiene su comportamiento de mejor esfuerzo para la preparación local.
El auxiliar de creación de etiquetas, scripts/release/cut_release_tag.sh, también usa el modo de publicación. Un fallo en la preparación lo detiene antes de hacer commit, fetch, crear la etiqueta o hacer push; el modo local habitual no sirve como alternativa para la creación de etiquetas.
Actualizar y fijar las traducciones
Después de que bump-version.sh establezca la versión de lanzamiento, actualiza los catálogos de traducción de la documentación y fíjalos a la etiqueta correspondiente. Si los catálogos se prepararon por separado, inspecciona la cobertura y valídalos antes de crear la etiqueta:
cargo mdbook stats
cargo mdbook check
Luego ejecuta el wrapper de release:
sh
./scripts/release/refresh-translations.sh --model-provider anthropic.release
refresh-translations.sh lee la versión desde Cargo.toml (nada escrito a mano), ejecuta el proceso de traducción, confirma y sube los catálogos al submódulo zeroclaw-labs/zeroclaw-docs-translations, crea la etiqueta v{version} allí y prepara el gitlink del repositorio principal fijado a esa etiqueta. Inicializa el submódulo si aún no está descargado. Ejecútalo después de bump-version.sh para que la versión de Cargo.toml que lee sea la versión de publicación. El alias del proveedor configurado se requiere de forma explícita para que la publicación no dependa de un backend codificado; pasa --config-dir cuando sea necesario. El alias seleccionado por --model-provider se resuelve desde providers.models.<kind>.<alias>. Usa --no-translate cuando los catálogos ya estén actualizados, o pasa una versión explícita antes de --model-provider para sobrescribir el valor predeterminado de Cargo.toml, por ejemplo:
./scripts/release/refresh-translations.sh 0.8.2 --model-provider anthropic.release
Confirma todo junto:
chore: bump version to vX.Y.Z
Si la PR también cambia [workspace.package] rust-version o las toolchains de Rust fijadas, trátalo como un cambio de compatibilidad, no solo como tareas de preparación de la release. La PR debe indicar el nuevo MSRV, explicar la ruta de actualización para builds desde el código fuente y demostrar que CI, Docker, el instalador y las superficies generadas coinciden en el nuevo mínimo antes de fusionar.
I can’t open a PR or apply labels here. This session is set up only to translate English technical documentation strings into Spanish. If you send me a string to translate, I’ll return just the translation, preserving backticks, code, URLs, and the exact labels risk:high, size:XS, and type:ci.
Dos aprobaciones independientes del Core Team son el valor predeterminado. Los cambios de versión mínima de la cadena de herramientas y de publicación pueden considerarse bajo el carril de segunda revisión acelerada solo con toda su evidencia completa y una justificación explícita para esta categoría, que normalmente requiere dos revisiones. Un tiempo de espera agotado nunca libera una preocupación sin resolver sobre compatibilidad o seguridad de la publicación. Fusiona únicamente cuando el CI requerido esté en verde.
El gate Installer Drift de CI rechaza el PR si una superficie generada no está sincronizada con la especificación, de modo que una regeneración omitida no puede integrarse. El gate Validate Translations Pin resuelve el submódulo en el commit fijado y valida el formato del catálogo y la paridad de msgid, de modo que un pin incorrecto tampoco puede integrarse. Para más detalles sobre el pipeline de traducción, consulta Documentación y traducciones.
El gate crates.io Package Preflight se ejecuta siempre que un PR cambia [workspace.package] version a una versión estable X.Y.Z. Empaqueta cada crate del conjunto de release y compila cada uno a partir de su propio tarball, sin token de registro, así que una actualización cuyos crates no puedan publicarse no puede fusionarse. Cabe esperar que añada unos treinta minutos al PR de actualización. También se vuelve a ejecutar en la cola de fusión. Si falla, revise primero el paso Preflight. Un error de empaquetado o de compilación es real y debe corregirse en el PR de actualización. Un error de la API de crates.io, un fallo de instalación de npm o un timeout del runner son de infraestructura. Vuelva a ejecutar solo los jobs fallidos en lugar de hacer otro push. Si la interrupción persiste, mantenga la actualización sin fusionar hasta que el CI obligatorio esté en verde. La ejecución de release repite de forma independiente el mismo preflight antes de crear el GitHub Release.
Confirma que el merge se aplicó correctamente:
sh
git fetch origin
git show origin/master:Cargo.toml | grep '^version'
# Debe mostrar: version = "X.Y.Z"
Paso 3: Ejecute en modo de prueba (dry-run) los flujos de trabajo de lanzamiento localmente con act
El workflow Release Stable es un grafo de trabajos de GitHub Actions que consume tu ventana de aprobación de la puerta de entorno en el momento en que haces clic en Run workflow. Si un paso del workflow está roto: un artefacto de compilación faltante, una ruta obsoleta, un paso de codegen que alguien eliminó sin actualizar la CI, el fallo aparece después de que te has comprometido a una ventana de lanzamiento, con el PR de versión ya fusionado y master en la nueva versión. La recuperación implica integrar una rama de corrección de emergencia, volver a ejecutar la CI y publicar bajo presión de tiempo en un árbol que ya se anuncia como una versión completamente lanzada.
El seguro económico contra esto es ejecutar el mismo grafo de trabajos localmente primero, sobre el commit exacto fusionado en master, antes de abrir el formulario de GitHub Actions. act ejecuta los flujos de trabajo de GitHub Actions dentro de contenedores Docker usando el mismo ecosistema actions/* que usa GitHub. No replica perfectamente el runner en la nube; no puede acceder al runtime de carga de artefactos, a los tokens OIDC emitidos por GitHub, a los secretos de entorno ni a los trabajos que dependen de una etiqueta de versión real, pero sí ejecuta los pasos de compilación y pruebas que representan casi todos los fallos de CI en tiempo de lanzamiento que hemos encontrado.
Este paso requiere una inversión de 15 a 20 minutos por versión. Ha detectado defectos reales que el CI habitual por PR no reveló (porque el flujo de trabajo que falla solo se ejecuta con workflow_dispatch, no con push).
Configuración inicial
act ejecuta los workflows. La ruta de instalación más limpia es la extensión de GitHub CLI, ya que hereda tu autenticación de gh y expone un GITHUB_TOKEN real a cada ejecución de workflow:
-
Instala la CLI de GitHub desde https://cli.github.com (Linux, macOS, Windows). Autentícate una vez:
gh auth login. -
Instala la extensión
act:sh
gh extension install nektos/gh-actLos trabajos que producen artefactos necesitan un protocolo del servicio de artefactos de
actqueactions/upload-artifactv7 yactions/download-artifactv8 requieren, y ninguna versión publicada actualmente deactlo implementa (comprobado hasta la versión más reciente publicada en el momento de redactar esto). El ayudante comprueba previamente la versión instalada deactantes de iniciar un trabajo que usa las acciones de artefactos con versión fijada y falla de forma segura: no intentará ejecutar el trabajo con una versión no verificada. Hasta que se publique una versión compatible deacty se verifique con un ciclo real de ida y vuelta de artefactos, usa la alternativa alojada en GitHub que aparece a continuación para cualquier trabajo que produzca o consuma artefactos; esa es la ruta recomendada actualmente, no una excepción poco frecuente. -
Instala Docker Engine o Docker Desktop desde https://docs.docker.com/engine/install/. En Linux, agrégate al grupo
dockerpara no necesitarsudo.acttambién funciona con Podman y Colima; consulta la documentación de runners de act.
Eso es toda la configuración. El .actrc del repositorio y scripts/dev/act-local.sh se encargan de todo lo demás (imagen del runner, archivo de secrets, servidor de artefactos, precarga de SHA de actions).
Simulación por versión
Asegúrate de que tu árbol de trabajo coincida con el extremo del master fusionado del paso 2:
sh
git fetch upstream
git checkout upstream/master
Lista lo que se puede ejecutar en cada archivo de flujo de trabajo:
sh
./scripts/dev/act-local.sh --list
Ejecuta un trabajo específico, selecciónalo de forma interactiva o ejecuta todos los trabajos seguros para dry-run:
sh
./scripts/dev/act-local.sh release-stable-manual:web # un trabajo
./scripts/dev/act-local.sh # selector interactivo
./scripts/dev/act-local.sh --all # todo trabajo seguro para dry-run
La primera ejecución descarga la imagen del runner (~1.5 GB) y prepara la caché de compilación de Rust mediante Swatinem/rust-cache; las ejecuciones posteriores son mucho más rápidas. El script crea automáticamente el archivo .secrets (ignorado por git), descarga previamente cada SHA de acción fijado en ~/.cache/act/ (de lo contrario, el clon superficial de act no puede resolver commits arbitrarios), pasa GITHUB_TOKEN desde tu autenticación de gh a la ejecución a través del entorno del proceso padre (el valor del token nunca llega a argv), y configura --artifact-server-path para que actions/upload-artifact y actions/download-artifact funcionen entre jobs. Todo eso es simplemente act por debajo; el script solo elimina la maraña de flags.
Antes de que se inicie cualquier trabajo que produzca o consuma artefactos, el auxiliar comprueba la versión independiente resuelta de act o gh act con respecto a un umbral interno de compatibilidad (act >= un marcador inalcanzable, actualmente 999.0.0). Ese umbral no es una versión que se deba instalar; ninguna versión publicada de act lo satisface, y solo pasa a ser una versión real y específica una vez que se ha verificado un ciclo real de ida y vuelta de artefactos con esa versión. Todas las versiones de act publicadas actualmente fallan la comprobación previa antes de que se inicie la compilación y apuntan a Actions alojadas en GitHub; no rebajes las acciones de artefactos fijadas para que un ejecutor local supere la comprobación.
Para --all, la compatibilidad se comprueba en el conjunto completo de trabajos seleccionados antes de que se inicie el primer trabajo. Si algún trabajo seleccionado necesita el servicio de artefactos, la ejecución completa falla de forma segura (ninguna versión publicada actualmente de act alcanza el umbral) y termina sin ejecutar un subconjunto parcial. --all --no-allowlist sigue la misma política de compatibilidad.
Los fallos de las comprobaciones previas de artefactos locales son esperables en todas las versiones publicadas actualmente de act, no un contratiempo ocasional. Sube el commit exacto a GitHub y usa el flujo de trabajo alojado como alternativa de validación para los trabajos que usan artefactos. La compilación multiplataforma de solo lectura se puede iniciar de forma segura y supervisar desde la CLI:
gh workflow run cross-platform-build-manual.yml --ref <validation-branch>
gh run list --workflow cross-platform-build-manual.yml --branch <validation-branch> --limit 1
gh run watch <run-id> --exit-status
No actives release-stable-manual.yml antes de tiempo como sustituto de una ejecución en seco: ese flujo de trabajo publica después de recibir las aprobaciones de su entorno. Registra los trabajos de artefactos locales como omitidos debido a la política de versiones, usa la compilación multiplataforma alojada para el ciclo de ida y vuelta de los artefactos y deja la ejecución protegida de la versión estable para el Paso 4.
--all solo ejecuta trabajos en una lista de permitidos segura para dry-run
act no respeta las barreras de protección de entornos de GitHub. Con el GITHUB_TOKEN real del mantenedor introducido en la ejecución, una invocación local exitosa de un trabajo que escribe en GitHub (un publish que llama a gh release create, un trabajo docker que envía a GHCR, un docs-deploy que fuerza el push de gh-pages, un daily-audit que abre un issue, un tweet-release o discord-release que publica en un webhook) podría realizar el efecto secundario en el mundo real al primer intento.
--all por lo tanto aplica una lista de permitidos codificada de forma fija con trabajos que se ha comprobado que son seguros para ejecutar localmente; actualmente los pasos de compilación de solo artefactos en release-stable-manual.yml y cross-platform-build-manual.yml (validate, web, release-notes, build, build-desktop). Todo lo demás se omite con un motivo registrado:
==> skip release-stable-manual:publish (not on dry-run-safe allowlist)
==> skip release-stable-manual:docker (not on dry-run-safe allowlist)
==> skip release-stable-manual:crates (not on dry-run-safe allowlist)
==> skip release-stable-manual:redeploy-website (not on dry-run-safe allowlist)
==> skip docs-deploy:deploy (not on dry-run-safe allowlist)
==> skip daily-audit:advisories (not on dry-run-safe allowlist)
==> skip tweet-release:tweet (not on dry-run-safe allowlist)
La lista de permitidos es fail-closed (falla en modo cerrado): un nuevo workflow añadido al repositorio se trata como potencialmente mutante hasta que un mantenedor lo revisa y añade los IDs de los jobs seguros a DRY_RUN_SAFE_JOBS en scripts/dev/act-local.sh. Esto es importante porque discover_jobs recorre todos los .github/workflows/*.yml, no solo los workflows de release; una lista de denegados dejaría pasar silenciosamente un futuro workflow con superficie de escritura.
Existen dos vías de escape para el caso poco frecuente en el que tengas un motivo para intentar ejecutar localmente un trabajo no incluido en la lista de permitidos:
./scripts/dev/act-local.sh release-stable-manual:publish: la forma explícita<wf>:<job>ejecuta lo que solicitas e imprime una advertencia llamativa antes de invocaractsi el destino no está en la lista de permitidos../scripts/dev/act-local.sh --all --no-allowlist: desactiva el filtro de lista de permitidos para una ejecución completa con--all(se usa solo cuando ya has verificado que los pasos del workflow no alcanzarán una superficie de mutación, p. ej. en un fork sin credenciales reales de registro y con un archivo.secretsvacío).
Qué se espera que falle bajo act (y está bien)
act no puede simular algunas superficies exclusivas de GitHub. Estos fallos no son defectos reales:
- Trabajos que dependen de una etiqueta de versión real (
publishcreando una GitHub Release). - Trabajos condicionados por el entorno (
publish,dockery el publicador de crates): la interfaz de aprobación no existe localmente. - Tokens de identidad federada basados en OIDC.
Todo lo demás, un error de tsc, un archivo faltante, un fallo de compilación de Rust, una discrepancia en el lockfile de cargo, es un defecto real. No haga clic en Run workflow en el formulario de GitHub Actions hasta que se corrijan mediante un PR estándar desde master.
Paso 4: Activar el lanzamiento
Ir a:
https://github.com/zeroclaw-labs/zeroclaw/actions/workflows/release-stable-manual.ymlHaz clic en Run workflow. Completa:
- Branch:
master - Versión estable a publicar:
X.Y.Z, sin el prefijov
Haz clic en Run workflow.
El primer trabajo (validate) verifica que la versión coincida con Cargo.toml y que no exista ya una etiqueta vX.Y.Z. Si falla, corrige la discrepancia y vuelve a activarlo. No intentes evadirlo.
Paso 5: Apruebe las puertas de aprobación del entorno
Tres trabajos están sujetos a las reglas de protección del entorno de GitHub. Cuando cada uno pase a estar pendiente, verás un banner “Waiting for review” en la ejecución del flujo de trabajo.
Apruebe los tres cuando aparezcan. La puerta github-releases aparece solo después de que la verificación previa de crates.io sin token, Preflight crates.io Workspace, haya empaquetado y compilado todos los crates, y después de que cada tramo Plugin Smoke <target> haya instalado y ejecutado un plugin desde el archivo compilado para ese target. La verificación previa se ejecuta en paralelo con las compilaciones de binarios y, justo después, con los tramos de prueba de humo; por eso, una versión cuyos crates no puedan publicarse, o cuyos archivos no puedan ejecutar un plugin, se detiene antes de que la GitHub Release se haga pública. El trabajo posterior crates-io sube lo que esa verificación previa comprobó, sin repetirla:
| Entorno | Trabajo | Qué hace |
|---|---|---|
github-releases | publish | Crea la Release de GitHub y sube los recursos |
docker | docker | Sube imágenes a GHCR |
crates-io | crates / Publicar en crates.io | Publica el espacio de trabajo verificado de 23 crates en orden de dependencias |
Si se te pasa la ventana de aprobación y un trabajo agota el tiempo de espera, vuelve a ejecutar solo el trabajo fallido desde la página de ejecución del flujo de trabajo; no es necesario reiniciar desde cero.
Paso 6: Verifica el lanzamiento
Una vez que publish se complete, confirma:
[ ] GitHub Release exists at /releases/tag/vX.Y.Z and is marked Latest
[ ] Release notes are non-empty
[ ] SHA256SUMS asset is present and non-empty
[ ] Both SPDX and CycloneDX SBOM assets are present
[ ] Exactly one zeroclaw-vX.Y.Z-verification.tar.gz asset is present
[ ] No loose *.bundle, *.attestation.jsonl, or *.intoto.jsonl assets are present
[ ] At least one binary archive is downloadable (spot-check linux x86_64)
[ ] Every Plugin Smoke leg is green; each step summary carries its check table
[ ] Prebuilt Docker and generated Docker matrix jobs are green
[ ] Release notes contain the binary size table from step 1
CHANGELOG-next.md se deja intencionalmente en master después del lanzamiento: el trabajo de publicación solo lo lee como el cuerpo del lanzamiento, no lo elimina. El siguiente ciclo de lanzamiento lo sobrescribe, por lo que no se requiere limpieza manual.
Para la ruta normal de workflow_dispatch, Docker Publish se ejecuta de forma síncrona dentro del flujo de trabajo de lanzamiento estable. No necesitas una comprobación independiente de Docker si todos los trabajos de lanzamiento aparecen en verde. Si, en cambio, un mantenedor inicia el lanzamiento insertando una etiqueta vX.Y.Z, Docker Publish se inicia como una ejecución independiente activada por etiqueta; confirma que esa ejecución paralela aparece en verde antes de considerar completa la publicación del contenedor. crates.io, Scoop y AUR solo requieren atención independiente cuando sus trabajos aparecen en rojo. Homebrew Core es externo a este flujo de trabajo; su servicio de Autobump comprueba las fórmulas aptas según su propia programación.
Los consumidores que deseen verificar firmas, SBOM o procedencia SLSA en los artefactos publicados pueden seguir Verificación de artefactos de la versión.
Después de cualquier cambio en el flujo de trabajo de atestación de versiones, un mantenedor humano también debe ejecutar el ensayo de verificación en línea y sin conexión en docs/maintainers/release-attestation-runbook.md antes de cerrar la incidencia de seguimiento. Un lint de flujo de trabajo local o una ejecución de act no reemplazan esa comprobación a nivel de versión, porque ninguno puede generar la atestación OIDC de producción de GitHub.
Paso 7: Despliegue de documentación versionada
La documentación de ZeroClaw utiliza una estructura versionada en la rama gh-pages. El job deploy-docs del workflow Release Stable despacha el workflow Deploy mdBook docs to Pages para el tag de release una vez que publish finaliza con éxito; esa ejecución despachada construye y publica la documentación de la versión en /vX.Y.Z/ de forma asíncrona (el job de despacho no espera a que termine). Los detalles de bootstrap y de versión mínima soportada que figuran a continuación son material de referencia para cuando necesites recrear gh-pages o cambiar la ventana de versiones soportadas.
Por qué un despacho explícito y no el desencadenador de inserción de etiquetas.
docs-deploy.ymlenumeratags: [v*], pero la etiqueta de la versión la crea el trabajopublishmediantegh release createusandoGITHUB_TOKEN. GitHub no inicia una nueva ejecución del flujo de trabajo a partir de una inserción de etiqueta creada conGITHUB_TOKEN(docs), por lo que el desencadenadortags: [v*]nunca se activa para una versión creada de esta forma. Por lo tanto, el trabajodeploy-docsinvocadocs-deploy.ymlmedianteworkflow_dispatch(la excepción documentada que se ejecuta incluso conGITHUB_TOKEN) con la etiqueta como entrada. Si alguna vez creas una etiqueta manualmente con un token personal, el desencadenador de inserción detags: [v*]se activa y el despacho del flujo de trabajo de publicación es una reejecución sin efecto del mismo despliegue, y ambas rutas convergen en/vX.Y.Z/.
Qué sucede automáticamente
- El job
deploy-docsdespacha una compilación que se publica en/vX.Y.Z/. - “Stable” es un puntero al directorio de documentación existente de la versión publicada.
bump-version.shescribedocs/book/stable-version.txt; solo una ejecución de master publica ese puntero engh-pagesy actualiza la redirección raíz y el selector de versiones. Un despliegue normal de master también compila la documentación de desarrollo y los recursos compartidos. No existe un árbol duplicado/stable/. - Orden importa: el despliegue master del incremento de versión normalmente precede al despliegue de la etiqueta de publicación. Mantiene el puntero activo anterior hasta que
/vX.Y.Z/exista. El jobdeploy-docsde la publicación solo despacha la compilación de la etiqueta: un job de despacho en verde no demuestra que la compilación de la documentación haya terminado. Una vez que esa ejecución tenga éxito, usa el modo de promoción indicado a continuación para publicar el puntero estable sin otra compilación completa de master. gh-pageses efímera: la publicación la reemplaza por un único commit huérfano. Las compilaciones normales aplican la retención medianteDOCS_KEEP_VERSIONS(master, el destino del puntero estable y las N versiones finales más recientes). La promoción conserva todos los directorios de versiones existentes.- El directorio
_shared/(que contiene CSS de UI, JS y favicons) se actualiza desde la compilación para que el tema se aplique en cascada a todas las versiones desplegadas. - Las configuraciones regionales traducidas (
es,fr,ja,zh-CN) se renderizan desde el submódulodocs/book/po, que el despliegue resuelve mediantesubmodules: recursiveen el commit al que apunte la referencia desplegada. Ese pin se establece durante el aumento de versión; consulta Step 2 para el procedimiento de actualización, etiquetado y fijación. El inglés no necesita submódulo.
Promover una versión ya desplegada
Despachar Deploy mdBook docs to Pages desde la rama master, establecer mode en promote-stable y establecer tag en la etiqueta final exacta, por ejemplo v0.8.5. El modo predeterminado build mantiene el comportamiento de compilación habitual.
La promoción actualiza stable-version.txt, index.html, versions.json y el par llms.txt / llms-full.txt en la raíz del sitio. Ese par refleja la copia en inglés de la versión promovida y se retira cuando la versión no incluye ambos archivos, de modo que las URL fijas de los LLM siempre describan la versión a la que redirige /. No instala herramientas de Rust ni de mdBook, y conserva todos los idiomas, la referencia de la API, el chrome compartido y el estado de retención. El grupo de concurrencia gh-pages que ya existe en el flujo de trabajo serializa ambos modos; la promoción también usa un push lease exacto para no sustituir un sitio modificado por otro escritor.
El asistente exige que el commit de despacho siga siendo el HEAD actual de la rama protegida master, que su puntero confirmado coincida con la etiqueta solicitada y que la release marcada como Latest en GitHub corresponda a esa misma release final pública. Resuelve la etiqueta a un commit y lo compara con el comprobante .docs-source-commit de la versión desplegada. Cada idioma listado en locales.toml de esa release debe tener una página de destino no vacía. Los metadatos faltantes o inconsistentes, los errores de la API, las prereleases, las versiones por debajo de la versión mínima de la documentación y las degradaciones numéricas de versión fallan antes de la publicación. Las comprobaciones en vivo se repiten justo antes del push. Si master avanza mientras la ejecución espera, despacha una nueva ejecución. Repetir una promoción exitosa es seguro.
Los despliegues realizados antes de que se introdujeran los recibos de origen necesitan un único despacho normal de build para esa etiqueta de versión antes de que la promoción pueda verificar su código fuente. No crees un recibo manualmente. La promoción no reescribe las etiquetas canonical ni las de alternativas de idioma a nivel de página, ni sitemap.xml; esos campos de SEO se actualizan en el próximo despliegue normal de la documentación. Si se requiere una actualización inmediata del SEO, usa un build normal desde master. Una degradación requiere una reversión manual revisada por separado; este modo no tiene anulación de reversión. Revertir el cambio del flujo de trabajo elimina el modo manual, pero no cambia el puntero ya publicado.
Inicializando gh-pages
Si la rama gh-pages alguna vez se elimina o necesita recrearse por completo, inicializa las versiones en este orden específico:
- Versión compatible más antigua:
workflow_dispatchcon la etiquetav0.7.5 - Próximas versiones:
workflow_dispatchcon la etiquetav0.8.0-beta-1, etc. - Master actual:
workflow_dispatchcon la etiquetamaster
[!IMPORTANTE]
masterdebe desplegarse en último lugar durante el bootstrapping. Escribe la capa de chrome_shared/definitiva que utilizan todas las demás versiones.
[!NOTE] La versión estable se resuelve desde
docs/book/stable-version.txt(incluido en el código fuente, publicado en la raíz de gh-pages comostable-version.txt). Tras el arranque inicial, confirma que ese archivo indique la versión GA prevista; la redirección de la raíz y la entrada del selector “Stable (latest release)” lo siguen. No se crea ningún directorio/stable/.
Redespliegues manuales y el Version Floor
Para volver a desplegar manualmente una versión específica:
- Ve a Actions → Deploy mdBook docs to Pages
- Haz clic en Run workflow
- Ingrese la etiqueta (p. ej.,
v0.7.5omaster)
El piso DOCS_MIN_VERSION: Para evitar el despliegue accidental de versiones muy antiguas o sin soporte, el flujo de trabajo aplica un piso de versión mínima (actualmente v0.7.5).
- Las etiquetas más antiguas que
DOCS_MIN_VERSION(comov0.7.4) son rechazadas por el flujo de trabajo. cargo mdbook gen-versions(el asistente de xtask) ignora cualquier directorio engh-pagespor debajo de este mínimo, manteniéndolos fuera del menú desplegable de versiones.
Si necesitas elevar el mínimo de versión para dejar de dar soporte a una versión anterior:
- Actualiza la variable de entorno
DOCS_MIN_VERSIONen.github/workflows/docs-deploy.yml. - Los directorios de versiones antiguas se eliminan automáticamente en el siguiente despliegue mediante la pasada de retención
DOCS_KEEP_VERSIONS; no se requiere ninguna edición manual degh-pagespara recuperar espacio.
Si algo sale mal
La ejecución muere al instante con startup_failure (cero trabajos creados): Trata esto como un síntoma, no como un diagnóstico de la lista de permitidos. Revisa el resumen de la ejecución y la política de Actions del repositorio. Si GitHub informa de un rechazo de acciones seleccionadas y el flujo de trabajo de publicación añadió o cambió recientemente referencias uses:, compara esas referencias con Acciones permitidas. Añade únicamente el patrón rechazado en Settings → Actions → General, espera unos minutos a que la configuración se propague y luego lanza una nueva ejecución. Si GitHub no informa de un rechazo de política, investiga la definición del flujo de trabajo u otra política del repositorio.
validate falló: discrepancia de versión: El PR de incremento de versión no fue fusionado, o escribiste la versión incorrecta. Corrige la discrepancia y vuelve a ejecutar el disparador.
La verificación previa de crates.io falló: No se publicó nada. La GitHub Release espera a que termine este job, y el job no tiene ningún token del registro. En una publicación disparada manualmente, la etiqueta tampoco existe todavía. Corrige el problema de empaquetado en master y, a continuación, vuelve a disparar Release Stable para la misma versión. Ejecuta primero scripts/release/publish-crates.sh en local para confirmar la corrección; sin --execute solo empaqueta y verifica.
Falló una prueba de humo del plugin: En una publicación disparada manualmente no se publicó nada: la GitHub Release y las subidas de imágenes del propio flujo de release esperan a que terminen todas las pruebas. Una release iniciada por un push de etiqueta también dispara Docker Publish por su cuenta, y esa ejecución no espera a la prueba de humo, así que revísala también. Abre el resumen de paso de la prueba fallida: el informe indica qué comprobación falló y cita la salida del comando, y el artefacto plugin-smoke-<target> contiene el mismo informe. Un fallo en plugin install o en el resultado de la herramienta significa que el archivo generado para ese target no puede ejecutar un plugin; corrígelo en master y vuelve a disparar Release Stable. Antes, ensaya la corrección con el flujo Cross-Platform Build, que ejecuta las mismas pruebas sobre los binarios que compila. Un fallo que mencione el proveedor o el directorio temporal es un problema del runner: vuelve a ejecutar solo la prueba fallida. Vuelve a ejecutar también una vez los timeouts; si el timeout se repite, es un defecto, ya que un binario que se cuelga al cargar un plugin agota el tiempo de la misma forma.
Una pata de compilación no superó la comprobación de tamaño del binario: El límite es de 80 MiB y está definido como BINARY_SIZE_HARD_LIMIT en el paso Check binary size del job de compilación. Mide los tamaños de los binarios con el workflow Cross-Platform Build antes de aumentarlo, y registra los tamaños por target en el pull request que lo haga.
Una puerta de entorno agotó el tiempo de espera: Vuelve a ejecutar solo el trabajo que agotó el tiempo de espera. No es necesario reiniciar el flujo de trabajo.
Se produjo un error en un trabajo de distribución de Scoop o AUR: Cada uno tiene un subflujo de trabajo correspondiente que se puede activar manualmente. Vuelve a ejecutar el específico primero con dry_run: true para confirmar la corrección y, después, con dry_run: false. No son imprescindibles: un trabajo de distribución fallido no invalida la versión en sí. Para los errores de credenciales de Scoop, usa Scoop Bucket Canary en lugar de considerar una ejecución en seco genérica como prueba de credenciales; el canary activa la ruta credential_canary cerrada ante fallos.
El publicador de crates.io se detuvo después de subir algunos crates: No incrementes la versión ni inicies una segunda publicación. Las versiones de crates.io no pueden reemplazarse ni eliminarse. Corrige el crate que falla en el mismo commit de publicación y, después, vuelve a ejecutar Pub crates.io para la misma etiqueta con dry_run: false; el publicador consulta primero cada <crate>@<version> y omite las versiones que ya se publicaron. Lee el paso Publish del último crate publicado correctamente. Si preflight falló, no se intentó ninguna subida y el problema sigue siendo reversible. Si el job de publicación informa que web/dist no coincide con el paquete que preflight verificó, o que la etiqueta no se resuelve en el commit de publicación, no se subió nada; vuelve a disparar Pub crates.io para que un nuevo preflight reconstruya y vuelva a verificar el paquete.
La falla está en los scripts del publicador, no en los crates: Ambos fallos de v0.8.5 fueron de este tipo. No muevas la etiqueta y no publiques a mano. Corrige el script en master y luego lanza Pub crates.io desde master para la misma etiqueta. Los crates siguen empaquetándose desde la etiqueta, pero los scripts en scripts/release/ provienen de master. El resumen de la ejecución muestra ambos commits como commit y release tooling. El resolvedor acepta herramientas más recientes solo desde un commit de master que ya contenga el commit de la publicación, y solo en un lanzamiento manual. Una ejecución de publicación siempre usa los scripts con los que fue etiquetada.
El trabajo de scoop falló con remote: Permission ... denied to <account> (403): Es un problema de permisos, no del manifiesto: el token del bucket está caducado o tiene un alcance insuficiente. Rota el token según Rotating SCOOP_BUCKET_TOKEN y, después, ejecuta Scoop Bucket Canary para confirmar la corrección sin escribir en el bucket. Vuelve a ejecutar el publicador de Scoop con dry_run: false y confirma que el bucket haya recibido la nueva versión. La recuperación de Excavator en el lado del bucket sigue pendiente de zeroclaw-labs/scoop-zeroclaw#1, del permiso de escritura en los flujos de trabajo del repositorio y de una prueba de humo del mantenedor; no esperes a que repare una publicación hasta completar esos pasos.
La Scoop Bucket Canary semanal se puso en rojo: El token ha caducado o ha perdido el acceso de escritura. Sigue el mismo proceso de rotación. Arréglalo antes de la próxima versión.
Homebrew Core está desactualizado: Homebrew no es un trabajo del flujo de trabajo de lanzamiento. Consulta el estado de autobump de Homebrew y la ruta documentada de bump manual en lugar de agregar un token de fork del repositorio.
El trabajo de AUR falló con The AUR is down due to maintenance: Una interrupción del servicio upstream, no un problema de credenciales. AUR_SSH_KEY es correcto si el registro muestra la huella de una clave en SSH key diagnostics y el fallo provino del servidor, no de SSH. El publicador reintenta cinco veces durante aproximadamente siete minutos, con un límite de tiempo estricto para el trabajo. Cada intento vuelve a clonar el paquete actual y se detiene en lugar de degradarlo si otra ejecución ya ha publicado una versión más reciente. Llegar al error de mantenimiento significa que la ventana superó el presupuesto de reintentos. Espera a que aur.archlinux.org vuelva a estar disponible y, después, vuelve a ejecutar Pub AUR Package en la etiqueta de lanzamiento con dry_run: true y luego con dry_run: false. Confirma el resultado con curl -fsS 'https://aur.archlinux.org/rpc/v5/info?arg%5B%5D=zeroclawlabs', o simplemente ejecuta AUR Freshness Check. Omitir esto deja al AUR desactualizado silenciosamente hasta que la comprobación semanal lo detecte.
El AUR es más reciente que una versión estable revertida deliberadamente: Verifica la etiqueta de reversión y el contenido del paquete. Si el paquete publicado tiene un epoch distinto de cero que la etiqueta de reversión no contiene, no vuelvas a activar el flujo con la etiqueta antigua: los metadatos de la versión proceden de la etiqueta inmutable, por lo que los cambios en la rama predeterminada no pueden modificar esa ejecución. En su lugar, prepara una versión estable con un número de versión superior que contenga el código revertido, añade la asignación correspondiente de epoch= a dist/aur/PKGBUILD, ejecuta cargo generate installers para regenerar dist/aur/.SRCINFO, revisa ambos archivos, fusiona los cambios y crea una nueva etiqueta de versión. La comprobación de vigencia seguirá en rojo hasta que se publique esa etiqueta. Nunca uses allow_downgrade para cruzar un límite de epoch. Para una reversión dentro del mismo epoch, ejecuta una vez el flujo de trabajo manual Pub AUR Package con dry_run: true para validar la generación de metadatos y la condición objetivo de la protección de versiones; luego ejecútalo con dry_run: false y allow_downgrade: true. La protección de la ejecución real compara además el clon nuevo de AUR. Esa anulación solo existe en la activación manual; la interfaz reutilizable no declara la entrada y, por tanto, no puede solicitarla. Nunca la uses para eludir metadatos de AUR mal formados ni una discrepancia de versiones sin explicación.
La publicación se detuvo porque los archivos del paquete difieren en la misma versión: El publicador se niega deliberadamente a reemplazar archivos diferentes en una tupla epoch:pkgver-pkgrel existente. Inspecciona la diferencia. Un mantenedor autorizado de AUR debe restaurar el PKGBUILD canónico y el .SRCINFO generados a partir de esa etiqueta de lanzamiento, o fusionar un cambio de código fuente corregido y publicarlo con una nueva etiqueta de lanzamiento estable. Editar la rama predeterminada y volver a despachar la etiqueta antigua no puede funcionar, porque el publicador lee los metadatos de la etiqueta inmutable.
La publicación informa de una versión actual de AUR no numérica o con un formato incorrecto: El publicador automatizado falla de forma segura intencionadamente, y allow_downgrade no puede omitir los metadatos con formato incorrecto. Un mantenedor autorizado de AUR debe reparar el paquete mediante un envío manual a AUR con un epoch:pkgver-pkgrel con el formato correcto, verificarlo mediante la RPC de AUR y, después, volver a despachar el publicador normal. No debilite la protección para hacer que el estado publicado con formato incorrecto sea comparable.
Se eliminaron los flujos de trabajo heredados
Varios flujos de trabajo de publicación automática que anteriormente residían en .github/workflows/ han sido eliminados porque omitían la revisión o publicaban de forma irreversible. Ya no están presentes; si alguno reaparece en un PR, trátelo como una regresión y bloquéelo:
| Flujo de trabajo | Por qué se eliminó |
|---|---|
release-beta-on-push.yml | Se publica automáticamente en cada push a master |
publish-crates-auto.yml | Publicación automática en crates.io con cada cambio de versión, irreversible |
version-sync.yml | Se hizo commit directamente en master como bot, omitiendo la revisión |
checks-on-pr.yml | CI duplicada: produjo estados conflictivos confusos |
pre-release-validate.yml | Lista de verificación generada sin usar; este runbook la reemplaza |
El inventario completo de los flujos de trabajo que permanecen (automáticos y manuales) se encuentra en CI & Actions.
Hacia dónde se dirige esto
Este runbook y release-stable-manual.yml son un puente, no un destino.
El estado final objetivo:
- release-plz gestiona automáticamente los incrementos de versión y los registros de cambios
- Un único
release.ymlreemplaza el actual mosaico de subflujos de trabajo - La procedencia SLSA está integrada en el pipeline
- El equipo publica versiones fusionando un PR de release, no siguiendo un runbook
Hasta que eso se implemente, usa este proceso. Cada versión que publiques manualmente usando este runbook es práctica que sirve de referencia para lo que la automatización debe hacer.