La refonte de ce matin posait une convention. Une convention qu'on n'outille pas tient tant que quelqu'un y pense : c'est le raisonnement de D-70, applique au corpus documentaire. Etat de depart mesure : 2 documents sur 34 declaraient leur lecteur. Les 32 autres disaient leur SUJET — ce qui avait enfoui le runbook de reprise le plus utile du depot au §6 de autorisation.md. Les 38 le declarent desormais, lecteur determine document par document et non colle au gabarit : l'exploitant (devis, migration de tenant, cycle de vie, gabarit d'or), le mainteneur (conceptions, registres, carte), le lecteur externe (ecosysteme-chezlepro), l'agent IA (MISE-A-JOUR-CODEX-CLAUDE). Deux exemptions DERIVEES, pas listees — un chemin en dur aurait vieilli a la premiere page ajoutee : un document qui s'annonce genere, et un fragment sans titre. Les 13 exemptes verifies un par un ; aucun document ecrit a la main n'est exempte par accident. La preuve ne lit que l'EN-TETE, ce qui empeche frontiere-opnsense.md et plan-et-generation.md — qui parlent de generation dans leur corps — d'etre exemptes a tort. Eprouvee dans les deux sens. Elle a echoue seule des sa premiere execution en nommant deux documents que mon inventaire avait manques (docs/audit/). Puis test negatif delibere : declaration retiree de meta-classe.md -> ECHEC la nommant ; restauree -> OK. Ce qu'elle ne teste pas : que le lecteur declare soit le BON. Ca se juge en revue ; elle garantit qu'on a du y penser. P01–P34. Comptes perimes corriges au passage (AGENTS.md et devis-services.md annoncaient encore 30 preuves). Verifie : prouver.py 0 (34 OK), plan-recette inchange. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.5 KiB
État de référence — avant reconstruction from-zero
Pour qui : qui compare après une reconstruction — le témoin contre lequel se lit toute divergence. Historique : il ne décrit pas l'état courant.
Figé le 2026-08-08, écosystème chezlepro (index 17, 14 VM), avant destruction et rejeu complet du plan. Ce document existe pour que « identique » soit prouvable plutôt que ressenti. Toute divergence après reconstruction se lit contre lui.
Les cinq devis, avant
identite CONFORME : le réel correspond au déclaré (1 compte(s) dans l'annuaire).
certificats CONFORME : aucun certificat servi n'est en fin de vie.
expositions CONFORME : toute exposition déclarée répond, des deux points de vue.
postgresql CONFORME : chiffrement imposé, et aucun réseau hors du supernet dérivé.
courriel CONFORME : la chaîne tient, de la résolution LDAP à la boîte.
Ce que la flotte porte
backup-01 10.27.18.21 1 service(s) metier
collab-01 10.27.21.21 3 service(s) metier
data-sql-01 10.27.18.11 2 service(s) metier
edge-mta-01 10.27.16.21 2 service(s) metier
forge-01 10.27.21.11 1 service(s) metier
idm-01 10.27.17.11 3 service(s) metier
infra-dns-01 10.27.19.11 1 service(s) metier
infra-edge-01 10.27.16.11 2 service(s) metier
infra-mail-01 10.27.19.31 2 service(s) metier
infra-pki-01 10.27.19.21 2 service(s) metier
mon-01 10.27.20.21 6 service(s) metier
obs-01 10.27.20.11 2 service(s) metier
web-dorsal-01 10.27.21.41 2 service(s) metier
web-frontal-01 10.27.21.31 2 service(s) metier
Ce qui sera perdu et devra être refait à la main
| Objet | Conséquence | Geste de reprise |
|---|---|---|
Clé racine de l'AC (/etc/step-ca/secrets/root_ca_key) |
la racine installée dans le navigateur devient inutile ; tous les certificats changent | make ca-racine + réinstaller, en comparant l'empreinte (§6.3) |
Mot de passe du compte sysadmin |
l'annuaire est recréé vide, puis amorcé | relever le jeton d'amorçage en voûte (§6.1) et le changer |
| Contenu applicatif (dépôts Forgejo, fichiers Nextcloud, courriels, tableaux Grafana) | non sauvegardé, non reconstructible par le code | aucun — assumé : c'est un POC |
Ce qui survit : les deux voûtes et
~/.config/setops-vault-passvivent hors dépôt et hors cluster ; le code est sureregion.chezlepro.ca(192.168.12.201), machine distincte du tenant. Rien de ce qui est nécessaire au rejeu n'est dans les 14 VM.
Après reconstruction — 2026-08-09
Écosystème détruit (14 VM, disques compris) puis rejoué depuis le plan seul. Aucune sauvegarde restaurée : ni LDAP, ni base, ni certificat, ni fichier.
identite CONFORME
certificats CONFORME
expositions CONFORME
postgresql CONFORME
courriel CONFORME
Cinq sur cinq, identiques à la référence. C'est la première fois que le dépôt peut dire que le système reconstruit est celui que le plan décrit — au lieu de dire que le dépôt est cohérent avec lui-même.
Les six défauts que seul un rejeu depuis zéro pouvait montrer
| # | Défaut | Pourquoi il dormait |
|---|---|---|
| 1 | amorcage_acces_courriel jamais déclaré par le tenant |
le compte existait déjà, le garde-fou n'avait jamais eu à se déclencher |
| 2 | rôles de realm créés après leur attachement aux groupes | un passage précédent les avait créés |
| 3 | claim de groupes posé avant les clients OIDC | les clients existaient déjà |
| 4 | écriture Keycloak annulée par le collecteur de transactions | la synchro LDAP complète ne se rejoue pas en exploitation |
| 5 | grafana-cli lancé avant que Grafana ait fini de démarrer |
le service tournait depuis toujours |
| 6 | port d'Alloy (12345) en collision avec le SASL de Dovecot | Alloy tenait le port ; c'est Dovecot qui échouait, en silence |
Trois défauts d'ordre, deux courses de premier démarrage, un conflit de port. Aucun n'était visible à un redéploiement, et aucun aux 31 preuves statiques — elles lisent le dépôt, pas la machine.
Le sixième mérite d'être relu : le conflit existait depuis toujours, mais dans l'autre
sens. Alloy tenait 12345 et l'écoute SASL de Dovecot échouait sans que personne ne le
voie. La reconstruction a inversé l'ordre de démarrage et rendu visible un défaut qui
était là depuis le début.
Ce qui a dû être refait à la main
- La base de Grafana : le premier démarrage, interrompu par le défaut nº 5, avait
laissé un schéma à moitié migré (
no such column: with_credentials). Base mise de côté, recréée par Grafana — 95 s pour lier son port, ce qui explique la course. - Rien d'autre. Ni certificat, ni compte, ni zone DNS, ni base de données.
Idempotence de la flotte — référence du 2026-08-09
Mesure faite après la seconde reconstruction, en rejouant make deployer-tout sur une
flotte intacte. Le dépôt n'avait jamais fait ce test à l'échelle de la flotte.
plays taches ok changed sautees
rejeu depuis zero 61 2152 924 443
2e passage 30 2249 17 ...
3e passage (apres) 30 2266 0 227
Zéro tâche changed, zéro échec.
Et ce zéro n'est pas du silence : plus de tâches se sont exécutées au passage à vide qu'au rejeu (2266 contre 2152). Elles ont toutes tourné, et toutes trouvé le système conforme. Un zéro obtenu avec moins de tâches aurait signifié l'inverse — des rôles qui ne font plus leur travail.
Ce que les 17 du deuxième passage cachaient
| Tâche | Ce que c'était vraiment |
|---|---|
13× Activer et demarrer node_exporter |
le service était mort — tué par SIGHUP à chaque renouvellement de certificat |
| 2× Prometheus | liste de cibles non ordonnée (intersect rend un ensemble) |
| 2× Forgejo | le dépôt faisait tourner le secret JWT du service à chaque déploiement |
Deux des trois n'étaient pas des défauts d'idempotence : c'étaient des pannes, qu'un
compte de changed a rendues visibles. La collecte de métriques s'arrêtait toutes les
24 heures sur les quatorze hôtes, et les jetons OAuth2 de la forge étaient invalidés à
chaque passage. Ni l'une ni l'autre ne se signalait autrement.
À quoi sert ce chiffre
Il devient la ligne de base. Un déploiement futur qui rapporte changed sur une flotte
non modifiée signale quelque chose : soit une dérive du système, soit un rôle qui a cessé
d'être idempotent. Tant que le fond était à 17, ce signal était noyé.