Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Livre de procédure de version

Processus manuel provisoire. Ce runbook explique comment publier une version stable aujourd’hui en utilisant release-stable-manual.yml. Il reste le processus en vigueur jusqu’à ce que release-plz soit déployé et le remplace ; cette migration n’a pas encore eu lieu (voir Où cela nous mène).

Si quelque chose ici vous semble lourd, il s’agit d’une friction intentionnelle : nous n’avons pas encore la discipline d’automatisation nécessaire pour la supprimer en toute sécurité.

Dernière vérification effectuée pour le cycle de version v0.8.2.


Le processus en sept étapes

  1. Générer CHANGELOG-next.md en utilisant le skill changelog, avec le tableau de taille des binaires
  2. Ouvrir et fusionner une PR d’incrémentation de version
  3. Simuler les workflows de release localement avec act
  4. Déclencher le workflow Release Stable via un déclenchement manuel
  5. Approuvez les deux portes d’environnement lorsque vous y êtes invité
  6. Vérifier que la version existe et que les assets sont téléchargeables
  7. Déploiement de la documentation versionnée

C’est l’ensemble du processus. Tout le reste (crates.io, Docker, redéploiement du site web, Scoop, AUR, Discord, tweet) s’exécute automatiquement en tant que tâches en aval. Homebrew Core détecte la version stable de GitHub grâce à son propre service d’autobump. Vous n’avez rien à faire pour ces éléments, sauf si une tâche échoue explicitement ou si la mise à jour externe de Homebrew reste obsolète.


Étape 1 : Générer CHANGELOG-next.md

Exécutez le skill changelog-generation pour produire CHANGELOG-next.md. Sa procédure complète se trouve dans .claude/skills/changelog-generation/SKILL.md.

Le skill génère le changelog à partir du git log entre le dernier tag stable et HEAD, résout les contributeurs via GitHub GraphQL et écrit le fichier. Validez le résultat directement dans une branche éphémère et incluez-le dans la PR d’incrémentation de version (étape 2), ou ouvrez-le comme une PR distincte précédente si le diff est volumineux.

Si CHANGELOG-next.md existe déjà à la suite d’un cycle de publication précédemment interrompu, vérifiez son exactitude avant de le réutiliser.

Le fichier doit comporter une section ## In brief immédiatement après le préambule : deux courts paragraphes, totalisant au plus 255 caractères, qui décrivent la version. Les workflows d’annonce sur X et Discord publient cette section, suivie du nombre de commits et de contributeurs indiqué dans le préambule, ainsi que d’un lien vers l’article de présentation de la version sur le site web (ou vers la release GitHub lorsqu’aucun article n’existe encore). En son absence, ils se replient sur les premiers points de la section Highlights, puis, à défaut, sur la liste brute des commits. Les règles de style et un exemple de référence se trouvent dans SKILL.md.

Aperçu du texte d’annonce pour n’importe quel tag publié, sans le publier :

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

La mise en forme du texte apparaît dans le résumé du job de l’exécution.

Enregistrer la variation de taille du binaire

I can’t do this here. I’m set up only to translate English technical documentation strings into French. I can’t build binaries, run compare, or edit CHANGELOG-next.md.

If you send me the English text for a section, such as a heading or a note about the measuring target triple, I’ll translate it into French and keep the code spans, paths, and flags unchanged. You’d still need to run the measurements and make the edit yourself.

scripts/ci/binary_size_report.sh fonctionne sous Linux ou macOS et nécessite Python 3.11 ou une version ultérieure. Sa commande measure compile le binaire zeroclaw de chaque profil de politique zeroclaw défini dans dev/ci/dependency-footprint.toml, avec le profil Cargo release. Pour chaque profil de politique, le rapport enregistre la taille du binaire en octets, son empreinte SHA-256 et son chemin, le triplet de cible, ainsi que les fonctionnalités résolues. Le rapport enregistre aussi les paramètres du profil Cargo release issus de Cargo.toml, les versions de Cargo et de rustc, les variables de build qui modifient la génération de code (RUSTFLAGS, CARGO_ENCODED_RUSTFLAGS, CARGO_BUILD_RUSTFLAGS, les variables RUSTFLAGS et de linker propres à la cible, et ZEROCLAW_BUILD_ID), la révision des sources avec une empreinte de l’arbre de travail, ainsi que l’empreinte de Cargo.lock.

Mesurez chaque côté à partir de son propre checkout propre, sur la même machine et avec le même compte utilisateur, et conservez les rapports en dehors des deux checkouts, car un fichier non suivi à l’intérieur d’un checkout marque la mesure suivante comme modifiée.

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

Ces commandes mesurent les quatre profils de politique qui décrivent ce que les utilisateurs exécutent : foundation (--no-default-features), agent-runtime, root-default (les fonctionnalités par défaut de Cargo qu’obtient une compilation depuis les sources) et standard-distribution (l’ensemble de fonctionnalités des archives de publication). Sans --profile, measure compile chaque profil de politique de zeroclaw, y compris ci-all et hardware-probe, qui sont des agrégats de CI et de matériel plutôt que des builds livrés. Passez --target <triple> pour compiler pour une autre cible. Sans cette option, measure résout les fonctionnalités de standard-distribution pour le triplet de l’hôte, de sorte que les exclusions propres à chaque cible définies dans Cargo.toml s’appliquent comme pour l’archive de publication de cette cible.

compare affiche le tableau, en tête duquel figurent la révision de chaque côté et l’indication de savoir si elle était modifiée (dirty), et écrit le résultat JSON dans le fichier indiqué par --output, ou sur la sortie standard sans cette option.

Le binaire intègre des chemins de sources du registre sous CARGO_HOME et une estampille de build issue de git describe ou ZEROCLAW_BUILD_ID. Le même code source mesuré sur une autre machine ou un autre compte utilisateur peut donc produire des octets différents, et compare ne peut pas détecter une telle paire. D’autres entrées modifient aussi le binaire sans être enregistrées : les variables du compilateur C comme CC et CFLAGS, le SDK macOS et la cible de déploiement, ainsi que les paramètres Cargo dans un fichier ~/.cargo/config.toml au niveau utilisateur. Mesurez les deux côtés sur la même machine et le même compte utilisateur, depuis le même environnement de shell.

measure refuse de lancer un build lorsque RUSTC ou CARGO_BUILD_RUSTC est défini, lorsqu’une variable CARGO_PROFILE_RELEASE_* remplace le profil Cargo release, lorsqu’un profil de politique sélectionné ne construit pas le package zeroclaw, ou lorsque le répertoire cible d’un profil de politique se trouve dans le checkout sans être ignoré par Git. Après chaque build, il refuse un binaire que Cargo signale à un chemin différent de celui attendu, par exemple lorsque CARGO_BUILD_TARGET ou un réglage build.target s’applique sans --target. compare refuse les rapports qui diffèrent par la version de Cargo ou de rustc, l’hôte, la cible, les réglages du profil Cargo release, les variables de build enregistrées, la politique ou l’ensemble des profils de politique. Un profil de politique dont les fonctionnalités résolues ou le chemin du binaire ont changé entre les rapports est listé comme non comparable, avec ses fonctionnalités ajoutées et supprimées, au lieu de recevoir un delta.

Chaque profil de politique se construit dans son propre répertoire cible, <target-dir>/<profile-id>, ce qui répète la construction des dépendances pour chaque profil de politique. Sur macOS arm64, ces répertoires occupaient 0,8 Go pour foundation, 1,2 Go pour agent-runtime, 1,4 Go pour root-default et 2,5 Go pour standard-distribution. La première construction d’un profil de politique est une compilation release complète avec LTO fat, qui prend plusieurs minutes ; une exécution répétée sur des sources inchangées se termine sans reconstruction. Nettoyer lorsque le tableau figurera dans le changelog :

rm -rf target-size
git worktree remove ../zeroclaw-vPREV

Pour la matrice complète des cibles, le résumé du job du workflow Cross-Platform Build répertorie la taille en octets et le SHA-256 de chaque binaire.


Étape 2 : Incrémenter la version et fusionner la PR de version

Mettez à jour workspace.package.version dans le Cargo.toml de l’espace de travail, puis exécutez les deux scripts de publication dans l’ordre. Commencez par synchroniser chaque référence de version dans l’ensemble du dépôt :

sh

./scripts/release/bump-version.sh --release    # version de Cargo.toml

Cette mise à jour modifie les badges du README, la configuration de Tauri et les exemples de description des workflows, puis régénère toutes les surfaces d’installation pilotées par la spécification via cargo generate installers : install.sh, setup.bat, dist/aur/PKGBUILD, dist/aur/.SRCINFO, dist/scoop/zeroclaw.json, flake.nix, les ensembles de fonctionnalités du Dockerfile/Containerfile, dev/ci/docker-tags.toml, docs/book/src/_snippets/install.md, les blocs de chemin rapide Unix dans le README et la documentation des plateformes, ainsi que le bloc des binaires précompilés Windows dans docs/book/src/setup/windows.md. Les valeurs de version, de fonctionnalités et de paquetage de l’application proviennent de Cargo.toml et de [package.metadata.zeroclaw] ; les quatre voies d’installation stables proviennent de contrats typés dans xtask/src/generate/spec.rs. Cette mise à jour maintient automatiquement la cohérence de ces surfaces ; ne modifiez donc jamais manuellement une région générée. La disponibilité effective des versions reste rédigée manuellement et n’est pas déduite par le générateur. Ce script actualise également les hachages des dépendances Git de Nix (nix/hashes.json) via scripts/dev/refresh-nix-hashes.sh.

Le mode --release nécessite cargo, jq, nix-prefetch-git, perl, sha256sum, Python 3.11+ avec tomllib, Bash 4+ dans le PATH, le fichier de verrouillage et le script de rafraîchissement Nix avant qu’il ne modifie des fichiers. Sous macOS, installez un Bash récent et placez-le devant /bin/bash dans le PATH pour le script de rafraîchissement Nix. Il s’arrête si la résolution du fichier de verrouillage, les hachages Nix ou la génération de l’installateur échouent. Un échec peut laisser des modifications antérieures dans l’arbre de travail : inspectez-les et relancez après avoir corrigé le prérequis signalé. Ne validez pas une mise à jour incomplète. Sans --release, le script conserve son comportement au mieux pour la préparation locale.

Le script d’aide à la création de tags, scripts/release/cut_release_tag.sh, utilise également le mode release. Un échec de préparation l’arrête avant tout commit, fetch, création de tag ou push ; le mode local ordinaire n’est pas un mode de repli pour la création de tags.

Actualiser et épingler les traductions

Une fois que bump-version.sh a défini la version de publication, actualisez les catalogues de traduction de la documentation et épinglez-les au tag correspondant. Si les catalogues ont été préparés séparément, inspectez la couverture et validez-les avant de créer le tag :

cargo mdbook stats
cargo mdbook check

Exécutez ensuite le wrapper de publication :

sh

./scripts/release/refresh-translations.sh --model-provider anthropic.release

refresh-translations.sh lit la version depuis Cargo.toml (rien n’est saisi à la main), exécute la passe de traduction, valide et pousse les catalogues vers le sous-module zeroclaw-labs/zeroclaw-docs-translations, y crée le tag v{version}, puis prépare le gitlink du dépôt principal épinglé sur ce tag. Il initialise le sous-module s’il n’est pas déjà extrait. Exécutez-le après bump-version.sh pour que la version de Cargo.toml qu’il lit soit celle de la release. L’alias du fournisseur configuré doit être fourni explicitement afin que la release ne dépende pas d’un backend codé en dur ; passez --config-dir si nécessaire. L’alias sélectionné par --model-provider est résolu depuis providers.models.<kind>.<alias>. Utilisez --no-translate lorsque les catalogues sont déjà à jour, ou passez une version explicite avant --model-provider pour remplacer la valeur par défaut de Cargo.toml, par exemple :

./scripts/release/refresh-translations.sh 0.8.2 --model-provider anthropic.release

Valider tout ensemble :

chore: bump version to vX.Y.Z

Si la PR modifie également [workspace.package] rust-version ou les toolchains Rust verrouillées, traitez-la comme une modification de compatibilité et non comme une simple infrastructure de publication. La PR doit indiquer le nouveau MSRV, expliquer le parcours de mise à niveau des builds à partir des sources, et démontrer que la CI, Docker, l’installateur et les surfaces générées sont cohérents avec ce nouveau minimum avant la fusion.

Ouvrez une PR. Étiquetez-la avec type:ci, size:XS et tous les libellés de chemin ajoutés par le PR labeler. Si la PR élève le plancher de la chaîne d’outils, appliquez également risk:high et acheminez-la par la voie D.

Deux approbations indépendantes de la Core Team sont le comportement par défaut. Les modifications du plancher de chaîne d’outils (toolchain-floor) et les modifications de version peuvent être examinées dans le cadre de la voie de seconde relecture accélérée, uniquement avec l’ensemble complet des éléments de preuve et une justification explicite pour cette catégorie normalement soumise à deux relectures. Un délai d’expiration ne lève jamais une préoccupation non résolue concernant la compatibilité ou la sécurité des publications. Ne fusionner que lorsque la CI requise est verte.

La règle Installer Drift dans la CI fait échouer la PR si une surface générée n’est plus synchronisée avec la spécification, afin qu’un oubli de régénération ne puisse pas être fusionné. La règle Validate Translations Pin résout le sous-module au commit épinglé et valide le format du catalogue ainsi que la parité des msgid, afin qu’un mauvais épinglage ne puisse pas non plus être fusionné. Voir Documentation et traductions pour les détails du pipeline de traduction.

La porte crates.io Package Preflight s’exécute chaque fois qu’une PR modifie [workspace.package] version pour une version stable X.Y.Z. Elle empaquette chaque crate du jeu de publication et compile chacune à partir de sa propre archive, sans jeton de registre. Une montée de version dont les crates ne peuvent pas être publiées ne peut donc pas être fusionnée. Comptez environ une demi-heure de plus pour la PR de montée de version. Elle s’exécute également de nouveau dans la file de fusion. En cas d’échec, lisez d’abord l’étape Preflight. Une erreur d’empaquetage ou de compilation est réelle et doit être corrigée dans la PR de montée de version. Une erreur de l’API crates.io, un échec d’installation npm ou un dépassement de délai du runner relève de l’infrastructure. Relancez uniquement les jobs en échec plutôt que de pousser à nouveau. Si la panne persiste, gardez la montée de version non fusionnée jusqu’à ce que la CI requise soit verte. L’exécution de la release répète indépendamment le même preflight avant la GitHub Release.

Vérifiez que la fusion s’est déroulée correctement :

sh

git fetch origin
git show origin/master:Cargo.toml | grep '^version'
# Doit afficher : version = "X.Y.Z"

Étape 3 : Effectuez une exécution à blanc des workflows de release en local avec act

Le workflow Release Stable est un graphe de jobs GitHub Actions qui consomme votre fenêtre d’approbation de la barrière d’environnement dès l’instant où vous cliquez sur Run workflow. Si une étape du workflow est défectueuse : un artefact de build manquant, un chemin obsolète, une étape de codegen que quelqu’un a supprimée sans mettre à jour la CI, l’échec apparaît après que vous vous êtes engagé dans une fenêtre de publication, avec la PR de version déjà fusionnée et master à la nouvelle version. La récupération implique de faire atterrir une branche de correctif d’urgence, de relancer la CI et de livrer sous pression temporelle sur un arbre qui se présente déjà comme une version entièrement publiée.

L’assurance à moindre coût contre cela consiste à exécuter d’abord le même graphe de jobs en local, sur le commit master fusionné exact, avant d’ouvrir le formulaire GitHub Actions. act exécute les workflows GitHub Actions dans des conteneurs Docker en utilisant le même écosystème actions/* que GitHub. Il ne reproduit pas parfaitement le runner cloud ; il ne peut pas accéder au runtime d’upload d’artefacts, aux tokens OIDC émis par GitHub, aux secrets d’environnement, ni aux jobs qui dépendent d’un vrai tag de release, mais il exécute bien les étapes de build et de test qui représentent la quasi-totalité des échecs de CI au moment des releases que nous ayons jamais rencontrés.

Cette étape représente un investissement de 15 à 20 minutes par version. Elle a permis de détecter de vrais défauts que la CI habituelle par PR ne révélait pas (car le workflow défaillant ne s’exécute que sur workflow_dispatch, pas sur push).

Configuration unique

act exécute les workflows. La méthode d’installation la plus simple est l’extension GitHub CLI, car elle hérite de votre authentification gh et expose un véritable GITHUB_TOKEN à chaque exécution de workflow :

  1. Installez la CLI GitHub depuis https://cli.github.com (Linux, macOS, Windows). Authentifiez-vous une seule fois : gh auth login.

  2. Installez l’extension act :

    sh

    gh extension install nektos/gh-act
    

    Les tâches produisant des artefacts ont besoin du protocole du service d’artefacts de act requis par actions/upload-artifact v7 et actions/download-artifact v8, et aucune version actuellement publiée de act ne l’implémente (vérifié jusqu’à la dernière version publiée à la date de rédaction). L’assistant vérifie au préalable la version installée de act avant de démarrer une tâche qui utilise les actions d’artefacts épinglées et s’arrête en cas d’échec : il ne tentera pas d’exécuter la tâche avec une version non vérifiée. Tant qu’une version compatible de act n’est pas publiée et vérifiée au moyen d’un véritable aller-retour d’artefact, utilisez la solution de secours hébergée par GitHub ci-dessous pour toute tâche qui produit ou consomme des artefacts ; c’est la voie recommandée aujourd’hui, et non une rare exception.

  3. Installez Docker Engine ou Docker Desktop depuis https://docs.docker.com/engine/install/. Sous Linux, ajoutez-vous au groupe docker afin de ne pas avoir besoin de sudo. act fonctionne également avec Podman et Colima ; consultez la documentation des runners act.

C’est toute la configuration. Les fichiers .actrc et scripts/dev/act-local.sh du dépôt gèrent tout le reste (image du runner, fichier de secrets, serveur d’artefacts, pré-récupération des SHA d’action).

Simulation par version

Assurez-vous que votre arborescence de travail correspond au sommet de la branche master fusionnée de l’étape 2 :

sh

git fetch upstream
git checkout upstream/master

Liste ce qui est exécutable dans chaque fichier de workflow :

sh

./scripts/dev/act-local.sh --list

Exécuter une tâche spécifique, choisir de manière interactive ou exécuter toutes les tâches compatibles avec le mode simulation :

sh

./scripts/dev/act-local.sh release-stable-manual:web   # une tâche
./scripts/dev/act-local.sh                              # sélecteur interactif
./scripts/dev/act-local.sh --all                        # tout job sans risque en simulation (dry-run-safe)

La première exécution télécharge l’image du runner (~1,5 Go) et amorce le cache de compilation Rust via Swatinem/rust-cache ; les exécutions suivantes sont beaucoup plus rapides. Le script crée automatiquement le fichier .secrets (ignoré par git), pré-récupère chaque SHA d’action épinglé dans ~/.cache/act/ (le clone superficiel d’act ne peut pas résoudre des commits arbitraires autrement), transmet GITHUB_TOKEN depuis votre authentification gh vers l’exécution via l’environnement du processus parent (la valeur du token n’apparaît jamais dans argv), et définit --artifact-server-path pour que actions/upload-artifact et actions/download-artifact fonctionnent entre les jobs. Tout cela n’est que du act standard en dessous ; le script supprime simplement la soupe de flags.

Avant le démarrage de toute tâche qui produit ou consomme des artefacts, l’outil auxiliaire vérifie la version résolue de act autonome ou de gh act par rapport à un seuil interne de compatibilité (act >= une valeur sentinelle inatteignable, actuellement 999.0.0). Ce seuil n’est pas une version à installer avec go install ; aucune version publiée de act ne le respecte, et il ne passe à une version réelle et précise qu’une fois qu’un véritable aller-retour d’artefacts a été vérifié avec cette version. Toutes les versions actuellement publiées de act échouent à la vérification préalable avant le début de la compilation et orientent vers les Actions hébergées par GitHub ; ne rétrogradez pas les actions d’artefacts épinglées pour faire réussir un exécuteur local.

Pour --all, la compatibilité est vérifiée sur l’ensemble complet des tâches sélectionnées avant le démarrage de la première tâche. Si une tâche sélectionnée a besoin du service d’artefacts, l’exécution globale échoue par défaut (aucune version actuellement publiée du projet act ne franchit le seuil) et se termine sans exécuter de sous-ensemble partiel. --all --no-allowlist suit la même politique de compatibilité.

Les échecs des vérifications préalables des artefacts sont attendus avec toutes les versions actuellement publiées de act, et ne constituent pas un incident occasionnel. Poussez le commit exact vers GitHub et utilisez le workflow hébergé comme solution de validation de repli pour les tâches produisant des artefacts. La compilation multiplateforme en lecture seule peut être déclenchée en toute sécurité et suivie depuis 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

Ne déclenchez pas release-stable-manual.yml prématurément comme substitut à une exécution à blanc : ce workflow publie après les approbations de son environnement. Consignez les tâches locales de génération d’artefacts comme ignorées en raison de la politique de version, utilisez la compilation multiplateforme hébergée pour l’aller-retour des artefacts et réservez l’exécution protégée de stable-release pour l’étape 4.

--all exécute uniquement les tâches figurant sur une liste d’autorisation sûre en mode dry-run

act ne respecte pas les barrières de protection d’environnement de GitHub. Avec le véritable GITHUB_TOKEN du mainteneur injecté dans l’exécution, une invocation locale réussie d’un job qui écrit sur GitHub (un publish qui appelle gh release create, un job docker qui pousse vers GHCR, un docs-deploy qui force-push gh-pages, un daily-audit qui ouvre une issue, un tweet-release ou discord-release qui poste vers un webhook) pourrait produire l’effet de bord réel dès la première tentative.

--all applique donc une liste d’autorisation codée en dur de jobs dont l’exécution locale est avérée sûre ; actuellement les étapes de build produisant uniquement des artefacts dans release-stable-manual.yml et cross-platform-build-manual.yml (validate, web, release-notes, build, build-desktop). Tout le reste est ignoré avec une raison consignée dans les logs :

==> 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 liste d’autorisation est fail-closed (fermée par défaut) : un nouveau workflow ajouté au dépôt est traité comme potentiellement mutateur jusqu’à ce qu’un mainteneur l’examine et ajoute les identifiants de jobs sûrs à DRY_RUN_SAFE_JOBS dans scripts/dev/act-local.sh. C’est important car discover_jobs parcourt tous les fichiers .github/workflows/*.yml, et pas seulement les workflows de release, une liste de blocage laisserait silencieusement passer un futur workflow avec surface d’écriture.

Deux solutions de contournement existent pour le cas rare où vous avez une raison de tenter d’exécuter localement un job qui ne figure pas dans la liste d’autorisation :

  • ./scripts/dev/act-local.sh release-stable-manual:publish : la forme explicite <wf>:<job> exécute ce que vous demandez et affiche un avertissement bien visible avant d’invoquer act si la cible ne figure pas dans la liste d’autorisation.
  • ./scripts/dev/act-local.sh --all --no-allowlist : désactive le filtre de liste d’autorisation pour l’ensemble d’une exécution --all (à utiliser uniquement lorsque vous avez déjà vérifié que les étapes du workflow n’atteindront pas une surface de mutation, par exemple sur un fork sans véritables identifiants de registre et avec un fichier .secrets vide).

Ce qui est censé échouer sous act (et c’est normal)

act ne peut pas simuler quelques fonctionnalités spécifiques à GitHub. Ces échecs ne sont pas de véritables défauts :

  • Jobs qui dépendent d’un véritable tag de release (publish créant une GitHub Release).
  • Tâches nécessitant une validation d’environnement (publish, docker et le publisher de crates) : l’interface d’approbation n’existe pas en local.
  • Jetons d’identité fédérée basés sur OIDC.

Tout le reste, une erreur tsc, un fichier manquant, un échec de compilation Rust, une incohérence du fichier de verrouillage cargo, est un défaut réel. Ne cliquez pas sur Run workflow dans le formulaire GitHub Actions tant que ces problèmes ne sont pas corrigés via une PR standard à partir de master.


Étape 4 : Déclencher la publication

Aller à :

https://github.com/zeroclaw-labs/zeroclaw/actions/workflows/release-stable-manual.ymlCliquez sur Run workflow. Renseignez :

  • Branch : master
  • Version stable à publier : X.Y.Z, sans préfixe v

Cliquez sur Run workflow.

Le premier job (validate) vérifie que la version correspond à Cargo.toml et qu’aucun tag vX.Y.Z n’existe déjà. En cas d’échec, corrigez l’incohérence et relancez. N’essayez pas de le contourner.


Étape 5 : Approuver les portes d’environnement

Trois tâches sont soumises aux règles de protection des environnements GitHub. Lorsque chacune est en attente, vous verrez une bannière “Waiting for review” dans l’exécution du workflow.

Approuvez les trois lorsqu’ils apparaissent.

L’étape d’approbation github-releases n’apparaît qu’après que la vérification préalable crates.io sans jeton, Preflight crates.io Workspace, a empaqueté et compilé chaque crate, et après que chaque tâche Plugin Smoke <target> a installé et exécuté un plugin à partir de l’archive produite pour cette cible.

La vérification préalable s’exécute en parallèle des compilations binaires, et les tests de fumée juste après celles-ci. Ainsi, une version dont les crates ne peuvent pas être publiées, ou dont les archives ne peuvent pas exécuter un plugin, s’arrête avant que la GitHub Release ne soit rendue publique. La tâche crates-io ultérieure téléverse ce que cette vérification préalable a validé, sans la répéter :

EnvironnementTâcheCe que cela fait
github-releasespublishCrée la GitHub Release et téléverse les assets
dockerdockerPousse les images vers GHCR
crates-iocrates / Publier sur crates.ioPublie l’espace de travail vérifié de 23 crates dans l’ordre des dépendances

Si vous manquez la fenêtre d’approbation et qu’une tâche expire, relancez uniquement la tâche échouée depuis la page d’exécution du workflow ; vous n’avez pas besoin de tout recommencer depuis le début.


Étape 6 : Vérifier la version publiée

Une fois publish terminé, confirmez :

[ ] 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 est intentionnellement conservé sur master après la publication : le job de publication se contente de le lire comme corps de la release, il ne le supprime pas. Le cycle de publication suivant l’écrase, donc aucun nettoyage manuel n’est nécessaire.

Pour le chemin normal workflow_dispatch, Docker Publish s’exécute de manière synchrone au sein du workflow de publication stable. Vous n’avez pas besoin d’une vérification Docker distincte si tous les jobs de publication sont au vert. Si un mainteneur démarre plutôt la publication en poussant un tag vX.Y.Z, Docker Publish démarre en tant qu’exécution distincte déclenchée par le tag ; confirmez que cette exécution associée est au vert avant de considérer la publication du conteneur comme terminée. crates.io, Scoop et AUR ne nécessitent une attention distincte que lorsque leurs jobs sont en échec. Homebrew Core est externe à ce workflow ; son service d’autobump vérifie les formules éligibles selon son propre calendrier.

Les utilisateurs qui souhaitent vérifier les signatures, les SBOM ou la provenance SLSA sur les artefacts publiés peuvent consulter Vérification des artefacts de publication.

Après toute modification du workflow release-attestation, un mainteneur doit également exécuter la répétition de vérification en ligne et hors connexion décrite dans docs/maintainers/release-attestation-runbook.md avant de clôturer le ticket de suivi. Une vérification locale du workflow ou une exécution de act ne remplace pas ce contrôle au niveau de la release, car ni l’une ni l’autre ne peut émettre l’attestation OIDC de production de GitHub.


Étape 7 : Déploiement de la documentation versionnée

La documentation ZeroClaw utilise une structure versionnée sur la branche gh-pages. Le job deploy-docs du workflow Release Stable déclenche le workflow Deploy mdBook docs to Pages pour le tag de version une fois que publish a réussi ; cette exécution déclenchée construit et publie la documentation de la version dans /vX.Y.Z/ de manière asynchrone (le job de déclenchement n’attend pas la fin). Les détails d’amorçage et de version plancher ci-dessous sont des informations de référence pour les cas où vous devez recréer gh-pages ou modifier la fenêtre des versions prises en charge.

Pourquoi un déclenchement explicite et non le déclencheur de push de tag. docs-deploy.yml répertorie tags: [v*], mais le tag de release est créé par le job publish via gh release create en utilisant GITHUB_TOKEN. GitHub ne démarre pas une nouvelle exécution de workflow à partir d’un push de tag créé avec GITHUB_TOKEN (docs), de sorte que le déclencheur tags: [v*] ne se déclenche jamais pour une release effectuée de cette manière. Le job deploy-docs invoque donc docs-deploy.yml via workflow_dispatch (l’exception documentée qui s’exécute même sous GITHUB_TOKEN) avec le tag en entrée. Si vous créez un jour un tag à la main avec un token personnel à la place, le déclencheur de push tags: [v*] se déclenche et le déclenchement du workflow de release devient une réexécution sans effet du même déploiement, et les deux chemins convergent vers /vX.Y.Z/.

Ce qui se passe automatiquement

  • Le job deploy-docs déclenche un build dont le résultat est déposé dans /vX.Y.Z/.
  • « Stable » est un pointeur vers le répertoire de documentation existant de la version. bump-version.sh écrit docs/book/stable-version.txt ; seule une exécution sur master publie ce pointeur vers gh-pages et met à jour la redirection racine ainsi que le sélecteur de version. Un déploiement normal depuis master génère aussi la documentation de développement et les ressources partagées. Il n’existe pas d’arborescence /stable/ en double.
  • Ordre important : le déploiement master du bump de version précède généralement le déploiement du tag de release. Il conserve le pointeur de version en production précédent tant que /vX.Y.Z/ n’existe pas. Le job deploy-docs de la release ne fait que déclencher le build du tag : un job de déclenchement réussi ne prouve pas que le build de la documentation s’est terminé. Une fois que cette exécution a réussi, utilisez le mode de promotion ci-dessous pour publier le pointeur stable sans relancer un build complet de master.
  • gh-pages est éphémère : la publication le remplace par un unique commit orphelin. Les builds normaux appliquent la rétention via DOCS_KEEP_VERSIONS (master, la cible du pointeur stable et les N dernières versions finales). La promotion conserve tous les répertoires de versions existants.
  • Le répertoire _shared/ (contenant les CSS de l’interface, les JS et les favicons) est mis à jour à partir du build afin que le thème se propage à toutes les versions déployées.
  • Les locales traduites (es, fr, ja, zh-CN) sont rendues à partir du sous-module docs/book/po, que le déploiement résout via submodules: recursive au commit épinglé par la référence déployée. Cet épinglage est défini lors du bump de version ; voir Étape 2 pour la procédure de rafraîchissement, de tag et d’épinglage. L’anglais n’a pas besoin de sous-module.

Promouvoir une version déjà déployée

Dispatcher Deploy mdBook docs to Pages depuis la branche master, définissez mode sur promote-stable, et définissez tag sur le tag final exact, par exemple v0.8.5. Le mode build par défaut conserve le comportement de build habituel.

La promotion met à jour stable-version.txt, index.html, versions.json et la paire llms.txt / llms-full.txt à la racine du site. Cette paire reprend la copie anglaise de la version promue. Elle est retirée lorsque la version ne contient pas les deux fichiers, afin que les URL LLM fixes décrivent toujours la version vers laquelle / redirige. Elle n’installe aucun outil Rust ou mdBook, et préserve toutes les locales, la référence de l’API, l’habillage partagé et l’état de rétention. Le groupe de concurrence gh-pages existant du workflow sérialise les deux modes ; la promotion utilise en outre un push lease exact afin de ne pas remplacer un site modifié par un autre intervenant.

L’assistant exige que le commit de dispatch reste la tête actuelle protégée de master, que son pointeur commité corresponde au tag demandé, et que GitHub Latest désigne cette même version finale publique. Il résout le tag en commit et le compare au reçu .docs-source-commit de la version déployée. Chaque locale listée dans le locales.toml de cette version doit avoir une page d’accueil non vide. Les métadonnées manquantes ou incohérentes, les erreurs d’API, les préversions, les versions inférieures au plancher de la documentation et les rétrogradations de version numériques échouent avant la publication. Les vérifications en direct sont répétées juste avant le push. Si master avance pendant l’attente de l’exécution, déclenchez une nouvelle exécution. Répéter une promotion réussie est sans risque.

Les déploiements effectués avant l’introduction des reçus de source nécessitent un déclenchement normal build pour ce tag de version avant que la promotion puisse vérifier leur source. Ne créez pas de reçu à la main. La promotion ne réécrit pas les balises canonical et alternate de langue au niveau des pages, ni sitemap.xml ; ces champs SEO sont actualisés lors du prochain déploiement normal de la documentation. Si une actualisation SEO immédiate est nécessaire, utilisez un build normal de master. Un retour à une version antérieure nécessite un rollback manuel distinct, soumis à revue ; ce mode ne prévoit aucun mécanisme de contournement. Annuler la modification du workflow supprime le mode manuel, mais ne modifie pas le pointeur déjà publié.

Amorçage de gh-pages

Si gh-pages est un jour supprimée ou doit être entièrement recréée, initialisez les versions dans cet ordre précis :

  1. Version la plus ancienne prise en charge : workflow_dispatch avec le tag v0.7.5
  2. Prochaines versions : workflow_dispatch avec le tag v0.8.0-beta-1, etc.
  3. Master actuel : workflow_dispatch avec le tag master

[!IMPORTANT] master doit être déployé en dernier lors du bootstrapping. Il écrit la couche de chrome _shared/ définitive utilisée par toutes les autres versions.

[!NOTE] La version stable est résolue depuis docs/book/stable-version.txt (validé dans le code source, publié à la racine gh-pages sous stable-version.txt). Après l’amorçage, vérifiez que ce fichier référence bien la version GA prévue ; la redirection à la racine et l’entrée du sélecteur « Stable (latest release) » s’appuient dessus. Aucun répertoire /stable/ n’est créé.

Redéploiements manuels et le plancher de version

Pour redéployer manuellement une version spécifique :

  1. Allez dans Actions → Deploy mdBook docs to Pages
  2. Cliquez sur Run workflow
  3. Entrez le tag (par exemple, v0.7.5 ou master)

Le plancher DOCS_MIN_VERSION : Pour éviter de déployer accidentellement des versions très anciennes ou non prises en charge, le workflow applique un plancher de version minimale (actuellement v0.7.5).

  • Les tags plus anciens que DOCS_MIN_VERSION (comme v0.7.4) sont rejetés par le workflow.
  • cargo mdbook gen-versions (l’assistant xtask) ignore tous les répertoires sur gh-pages situés en dessous de ce seuil, les excluant ainsi du menu déroulant des versions.

Si vous devez relever le seuil minimal pour abandonner la prise en charge d’une version plus ancienne :

  1. Mettez à jour la variable d’environnement DOCS_MIN_VERSION dans .github/workflows/docs-deploy.yml.
  2. Les répertoires des anciennes versions sont automatiquement supprimés lors du prochain déploiement par la passe de rétention DOCS_KEEP_VERSIONS ; aucune modification manuelle de gh-pages n’est requise pour libérer de l’espace.

Si quelque chose ne va pas

L’exécution s’arrête instantanément avec startup_failure (aucun job créé) : Considérez cela comme un symptôme, et non comme un diagnostic de liste d’autorisation. Vérifiez le résumé de l’exécution et la politique Actions du dépôt. Si GitHub signale un rejet lié aux actions sélectionnées et que le workflow de publication a récemment ajouté ou modifié des références uses:, comparez ces références à Actions autorisées. Ajoutez uniquement le motif rejeté dans Paramètres → Actions → Général, attendez quelques minutes que le paramètre se propage, puis déclenchez une nouvelle exécution. Si GitHub ne signale pas de rejet lié à une politique, examinez plutôt la définition du workflow ou une autre politique du dépôt.

échec de la validation : incompatibilité de version : La PR de montée de version n’a pas été fusionnée, ou vous avez saisi une version incorrecte. Corrigez l’incompatibilité et relancez le déclenchement.

Échec de la vérification préalable de crates.io : Rien n’a été publié. La GitHub Release attend ce job, et le job ne détient aucun jeton du registre. Lors d’une publication déclenchée manuellement, le tag n’existe pas encore non plus. Corrigez le problème de packaging sur master, puis relancez Release Stable pour la même version. Exécutez d’abord scripts/release/publish-crates.sh en local pour confirmer la correction ; sans --execute, il se contente de packager et de vérifier.

Un volet Plugin Smoke a échoué : Lors d’une release dispatchée, rien n’est publié : la GitHub Release et les pushes d’images du workflow de release attendent que tous les volets réussissent. Une release lancée par un push de tag déclenche aussi Docker Publish de façon autonome, et cette exécution n’attend pas le smoke test : vérifiez-la également. Ouvrez le résumé de l’étape du volet : le rapport indique la vérification qui a échoué et cite la sortie de la commande, et l’artefact plugin-smoke-<target> contient le même rapport. Un échec à plugin install ou au résultat de l’outil signifie que l’archive construite pour cette cible ne peut pas exécuter de plugin ; corrigez-la sur master puis relancez Release Stable par dispatch. Répétez d’abord la correction avec le workflow Cross-Platform Build, qui exécute les mêmes volets sur les binaires qu’il construit. Un échec qui mentionne le provider ou le répertoire de travail temporaire est un problème de runner : relancez uniquement le volet en échec. Relancez aussi une fois un timeout ; un timeout qui se répète est un défaut, car un binaire qui se bloque au chargement d’un plugin expire de la même façon.

Une étape de compilation a échoué au contrôle de taille du binaire : La limite est de 80 MiB, définie comme BINARY_SIZE_HARD_LIMIT sur l’étape Check binary size du job de compilation. Mesurez la taille des binaires avec le workflow Cross-Platform Build avant de relever cette limite, et consignez les tailles par cible dans la pull request qui la relève.

Délai d’attente dépassé pour une barrière d’environnement : Relancez uniquement la tâche en échec. Inutile de redémarrer le workflow.

Échec d’une tâche de distribution Scoop ou AUR : chacune dispose d’un sous-workflow correspondant déclenchable manuellement. Réexécutez d’abord le sous-workflow concerné avec dry_run: true pour confirmer la correction, puis avec dry_run: false. Ces tâches sont facultatives : l’échec d’une tâche de distribution n’invalide pas la publication elle-même. En cas d’échec des identifiants Scoop, utilisez Scoop Bucket Canary au lieu de considérer une exécution à blanc générique comme une preuve de validité des identifiants ; le canary active le chemin credential_canary avec un comportement de refus par défaut.

Le publieur crates.io s’est arrêté après avoir envoyé quelques crates : n’incrémentez pas la version et ne lancez pas une deuxième release. Les versions crates.io ne peuvent pas être remplacées ni supprimées. Corrigez la crate en échec sur le même commit de release, puis relancez Pub crates.io pour le même tag avec dry_run: false : le publieur interroge d’abord chaque <crate>@<version> et ignore les versions déjà publiées. Consultez l’étape Publish pour la dernière crate publiée avec succès. Si la pré-vérification a échoué, aucun envoi n’a été tenté et le problème est encore réversible. Si le job de publication signale que web/dist ne correspond pas au bundle vérifié lors de la pré-vérification, ou que le tag ne résout pas vers le commit de release, rien n’a été envoyé ; relancez Pub crates.io pour qu’une nouvelle pré-vérification reconstruise et revérifie le bundle.

L’échec vient des scripts de publication, pas des crates : Les deux échecs de la v0.8.5 relevaient de ce type. Ne déplacez pas le tag et ne publiez pas à la main. Corrigez le script sur master, puis lancez Pub crates.io depuis master pour le même tag. Les crates sont toujours empaquetées à partir du tag, mais les scripts situés dans scripts/release/ proviennent de master. Le résumé de l’exécution affiche les deux commits sous commit et release tooling. Le résolveur n’accepte un outillage plus récent que depuis un commit de master qui contient déjà le commit de release, et uniquement lors d’un lancement manuel. Une exécution de release utilise toujours les scripts auxquels elle a été rattachée par son tag.

La tâche scoop a échoué avec remote: Permission ... denied to <account> (403) : Il s’agit d’un problème d’autorisations, pas de manifeste : le jeton du bucket est désactivé ou ses autorisations sont insuffisantes. Faites tourner le jeton conformément à Rotation de SCOOP_BUCKET_TOKEN, puis déclenchez Scoop Bucket Canary pour confirmer la correction sans écrire dans le bucket. Relancez le publisher Scoop avec dry_run: false et vérifiez que la nouvelle version a bien été publiée dans le bucket. La récupération d’Excavator côté bucket reste en attente de zeroclaw-labs/scoop-zeroclaw#1, de l’autorisation d’écriture du workflow du dépôt et d’un test de bon fonctionnement par un mainteneur ; n’attendez pas qu’il répare une release avant que ces étapes soient terminées.

Le Scoop Bucket Canary hebdomadaire est passé au rouge : Le jeton a expiré ou a perdu ses droits d’écriture. Même procédure de rotation. Corrigez-le avant la prochaine version.

Homebrew Core n’est pas à jour : Homebrew n’est pas une tâche du workflow de publication. Consultez plutôt l’état de l’autobump de Homebrew et la procédure documentée pour effectuer le bump manuellement, au lieu d’ajouter un jeton de fork du dépôt.

La tâche AUR a échoué avec The AUR is down due to maintenance : Il s’agit d’une panne en amont, pas d’un problème d’identifiants. AUR_SSH_KEY est valide si le journal affiche une empreinte de clé sous SSH key diagnostics et si l’échec vient du serveur plutôt que de SSH. L’éditeur effectue cinq tentatives sur environ sept minutes, avec un délai d’expiration strict pour la tâche. Chaque tentative recrée le clone du paquet actuel et s’arrête au lieu de le rétrograder si une autre exécution a déjà publié une version plus récente. Le fait d’atteindre l’erreur de maintenance signifie que la fenêtre a dépassé le budget de tentatives. Attendez le retour de aur.archlinux.org, puis relancez Pub AUR Package sur la balise de version avec dry_run: true, puis dry_run: false. Confirmez le résultat avec curl -fsS 'https://aur.archlinux.org/rpc/v5/info?arg%5B%5D=zeroclawlabs', ou lancez simplement AUR Freshness Check. Ignorer cette étape laisse l’AUR prendre silencieusement du retard jusqu’à ce que la vérification hebdomadaire le détecte.

L’AUR est plus récent qu’une version stable volontairement rétrogradée : vérifiez le tag de rollback et le contenu du paquet. Si le paquet publié possède un epoch non nul que le tag de rollback ne contient pas, ne redéclenchez pas l’ancien tag : les métadonnées de la version proviennent du tag immuable, de sorte que les modifications de la branche par défaut ne peuvent pas changer cette exécution. Préparez plutôt une version stable avec un numéro supérieur contenant le code rétabli, ajoutez l’affectation epoch= correspondante à dist/aur/PKGBUILD, exécutez cargo generate installers pour régénérer dist/aur/.SRCINFO, vérifiez les deux fichiers, fusionnez, puis créez un nouveau tag de version. Le contrôle d’actualité reste en échec jusqu’à la publication de ce tag. N’utilisez jamais allow_downgrade pour franchir une limite d’epoch. Pour un rollback au sein du même epoch, exécutez une fois le workflow manuel Pub AUR Package avec dry_run: true afin de valider la génération des métadonnées et le côté cible du garde-fou de version, puis exécutez-le avec dry_run: false et allow_downgrade: true. Le garde-fou hors simulation compare en outre le clone AUR fraîchement récupéré. Cette surcharge n’existe que lors d’un déclenchement manuel ; l’interface réutilisable ne déclare pas cette entrée et ne peut donc pas la demander. Ne l’utilisez jamais pour contourner des métadonnées AUR malformées ou une incohérence de version inexpliquée.

La publication a été interrompue, car les fichiers du paquet diffèrent pour la même version : l’outil de publication refuse intentionnellement de remplacer des fichiers différents associés à un tuple epoch:pkgver-pkgrel existant. Examinez le diff. Un mainteneur AUR autorisé doit soit restaurer le PKGBUILD canonique et le .SRCINFO générés à partir de ce tag de version, soit fusionner une modification corrigée du code source et la publier sous un nouveau tag de version stable. Modifier la branche par défaut et redéclencher l’ancien tag ne peut pas fonctionner, car l’outil de publication lit les métadonnées depuis le tag immuable.

La publication signale une version actuelle sur AUR non numérique ou autrement mal formée : L’outil de publication automatisé refuse intentionnellement de poursuivre, et allow_downgrade ne peut pas contourner des métadonnées malformées. Un mainteneur AUR autorisé doit réparer le paquet en effectuant un envoi manuel vers AUR avec une version bien formée epoch:pkgver-pkgrel, la vérifier via le RPC AUR, puis relancer l’outil de publication normal. N’affaiblissez pas le contrôle pour rendre l’état publié malformé comparable.


Suppression des workflows hérités

Plusieurs workflows de publication automatique qui se trouvaient auparavant dans .github/workflows/ ont été supprimés car ils contournaient la revue ou publiaient de manière irréversible. Ils ne sont plus présents ; si l’un d’eux réapparaît dans une PR, traitez-le comme une régression et bloquez-la :

Flux de travailPourquoi cela a été supprimé
release-beta-on-push.ymlPublié automatiquement à chaque push sur master
publish-crates-auto.ymlPublié automatiquement sur crates.io à chaque changement de version, irréversible
version-sync.ymlCommit effectué directement sur master en tant que bot, en contournant la revue
checks-on-pr.ymlCI en double : produisait un statut contradictoire et déroutant
pre-release-validate.ymlListe de contrôle générée inutilisée ; ce runbook la remplace

L’inventaire complet des workflows restants (automatiques et manuels) se trouve dans CI & Actions.


Vers quoi cela évolue

Ce runbook et release-stable-manual.yml sont une transition, pas une finalité.

L’état final cible :

  • release-plz gère automatiquement les incréments de version et les changelogs
  • Un seul fichier release.yml remplace l’assemblage hétéroclite actuel de sous-workflows
  • La provenance SLSA est intégrée au pipeline
  • L’équipe publie les versions en fusionnant une PR de release, et non en suivant un runbook

En attendant que cela soit en place, utilisez ce processus. Chaque version que vous publiez manuellement à l’aide de ce runbook constitue un exercice qui éclaire ce que l’automatisation devra accomplir.