Commit graph

67 commits

Author SHA1 Message Date
a204ead8ab pre-vol M4 : raser et le devis de placement nomment le locataire designe
Sur le chemin TENANT=, raser annoncait un ecosysteme monte (rien n'est
monte sur le runner du site) et le devis de placement un tenant « ? ».
Les deux en-tetes disent desormais ce qui est vise et d'ou vient la liste.
Le pre-vol lui-meme est consigne : 13 VM, aucun conflit, placement conforme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:16:04 -04:00
e7f1a74040 contexte : materialisation M3, la reconstruction nomme son locataire
reconstruire_locataire lance locataire-raser et locataire-creer TENANT= sur
le runner du site, sans monter le depot du locataire comme instance.

Trou de M2 corrige avant tout usage : le sous-make cloner-vm nommait le pool
par l'instance montee (hors de tout pool sur le site, pool de l'autre
locataire sur le poste). devis_proxmox_pools.py --pool-du-locataire le
derive de la face.

test_appels_locataire.py : un faux ansible-playbook consigne la ligne qui
part ; 26 machines, ancien chemin, site et poste identiques a l'argument
pres. Temoin : l'ancienne ligne de pool fait echouer le test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:27:25 -04:00
8294e5dc71 contexte : materialisation M2, les commandes du site nomment leur locataire
locataire-creer, locataire-raser et placement-plan TENANT= lisent la face
reseau du locataire, sans monter son depot comme instance. flotte-creer,
creer-vm et raser acceptent TENANT= ; sans lui, l'ancien chemin est inchange.

P94 : creer, raser et placer par la face visent les memes machines, VMID,
valeurs et ponts que l'ancien chemin, chacun mesure par sa commande lancee
a part. 116 controles dans test_contexte.py, temoins compris.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:08:21 -04:00
4532a98707 contexte : materialisation M1, la face publie les parametres de clonage (P93)
Chaque machine porte ce que parametres-proxmox rend, par la meme fonction.
P93 compare a la commande lancee a part pour les 26 machines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 15:22:43 -04:00
40af2d1ec6 contexte : etape 3, les pools et les tunnels lisent la face reseau
devis_proxmox_pools et vpn_admin prennent machines, VMID, etat, pairs et
index dans la face publiee. Sorties identiques a un worktree complet de
la version precedente ; temoins d'alteration verts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 14:59:29 -04:00
2e9b31bef7 contexte : corriger le devis des pools vide (face sans fonctions)
La face publie aussi fonctions ; les pools retrouvent leurs VM. La
comparaison a l'ancien code est refaite dans un git worktree complet :
les sept sorties du site sont identiques. Garde de regression ajoutee.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 14:49:24 -04:00
d0a6002b87 contexte : etape 3, le site decouvre ses locataires par leur face reseau
decouvrir_du_site part de underlay.tenants et prend index et zones dans
la face publiee. Les sept sorties du site sont identiques a HEAD, a
l'octet pres ; frontiere-plan ne voit rien a faire.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:10:39 -04:00
013c1b5279 contexte : etape 3, la frontiere lit la face reseau
devis_opnsense prend dans la face publiee les adresses des groupes,
l'intrant d'administration, les verdicts, le tunnel et les zones
publiees. Devis identique a l'octet pres, a HEAD comme par le repli.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:02:03 -04:00
8c1e8c725b contexte : etape 3, le pare-feu Proxmox lit la face reseau
La face publie le verdict des flux conditionnels ; devis_proxmox_fw y lit
inventaire, verdicts et administration. Devis identique, octet pour octet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 12:51:37 -04:00
44c24e62e4 contexte : etape 3, le locataire publie sa face reseau, le site la lit (P92)
face-reseau.yml publiee chez chaque locataire (make face-reseau-publier) ;
les comptes de sauvegarde et le DNS public du site la lisent au lieu des
fichiers internes. Inventaire du site identique, octet pour octet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 12:39:28 -04:00
2beef04dc6 contexte : etape 3, l'instancier lit la fiche du site (P91)
Le site depose fiche-site.yml chez ses locataires (make fiches-site-
deposer) ; l'instancier y lit temps, delegation DNS et routage. Sans le
site, l'inventaire genere est identique au versionne, a l'octet pres.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 12:23:17 -04:00
d6591cb271 contexte : etape 2 terminee, les sorties (P90)
resoudre_flux publie les sorties vers l'Internet de chaque machine ;
verifier_sorties les confronte aux regles de sortie de la frontiere.
Le contrat site <-> locataire est entierement publie et prouve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 11:21:37 -04:00
ce84d0e1ea frontiere : l'administration (P89) ; serveur_ops ne declare plus le 8006
La face reseau dit quelles entrees publiques sont ouvertes au poste ;
verifier_administration confronte gestion, VPN et tunnel. La sortie 8006
de serveur_ops vers externe ne laissait passer aucun paquet (hyperviseurs
en plages privees) et affirmait un pouvoir qu aucun locataire n a.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 03:14:14 -04:00
3c16ef45cd contexte : etape 2, la frontiere second temps, les entrees publiques (P88)
La face reseau porte le port de son tunnel ; verifier_entrees_publiques
confronte regles WAN, redirections et tunnel aux entrees que la face
ouvre a tous. Aucun ecart ; quatre alterations vues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:14:32 -04:00
78c2c25761 contexte : etape 2, la frontiere premier temps, les identites (P87)
La face reseau porte ses zones ; verifier_frontiere confronte supernet,
administration, tunnel, alias de groupe, routes et traduction sortante a
la face reseau et a la fiche du site. Aucun ecart ; cinq alterations vues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 23:28:06 -04:00
3d01208a68 contexte : etape 2, les flux de chaque machine (P86)
La face reseau porte les flux resolus par le locataire ; verifier_flux
les confronte au devis Proxmox, port par port. resoudre_flux publie les
sources_declarees d un port aussi public, que le locataire jetait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 23:10:12 -04:00
077c6c91b4 contexte : etape 2b, la face reseau du locataire (les faits)
locataire.face_reseau() publie index, machines, groupes, administration,
zones publiques et cle de sauvegarde ; verifier_face la confronte aux
consommateurs du site (decouverte, devis Proxmox, frontiere, inventaire
du site). P85 : aucun ecart ; huit alterations vues en ecart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 21:02:29 -04:00
8251022148 contexte : etape 2a, la fiche du site et la preuve qu elle dit vrai
site.fiche_pour(locataire) reunit attribution, offre, racine et les
trois lectures directes de l instancier ; verifier_fiche la confronte
aux copies, a la racine et a l inventaire du locataire. P84 : aucune
ecart sur les deux couples ; sept alterations vues en ecart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:16:55 -04:00
c891d7fb26 contexte : etape 1, le tronc commun et les deux classes (inutilises)
scripts/contexte.py : Ecosysteme, Site, Locataire, contexte actif
(fichier `contexte`, sinon les indices d avant via instance_courante
et underlay.chemin). 40 controles dans make test. Corrige aussi P34 et
P48, rouges depuis le commit de la page de conception.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 19:43:20 -04:00
f42d30b38a validation avant release : test casse par (74), trois defauts d outillage
test_restauration fournit client_backup_attente_verrou et exige
--retry-lock ; test_frontiere_refus lit le WAN sous if_wan ; prouver
--verifier nomme les preuves en echec ; le Makefile n exporte plus une
liste de cles de voute vide (valeur identique sur le poste).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 15:46:43 -04:00
6a8fc53084 frontiere : les interfaces internes refusent a voix haute, le WAN reste muet
Un reject final, journalise, sur chaque interface interne (zones du site,
gestion, transit, WireGuard) : un flux mal declare entre deux zones echoue
au lieu d'expirer. P53 affinee, P50 ne compte que les block, test du devis.
La sonde classe ECONNREFUSED en avertissement : le RST de la frontiere est
indiscernable d'un port ferme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 15:39:46 -04:00
7a2f179f39 repertoires partages : un seul mode par repertoire ; le depot de binaires du site sert de nouveau
/var/lib/setops etait tenu par quatre roles (0750 contre 0755) : apt-cacher-ng
ne le traversait plus, le depot rendait 403 et chaque runner reconstruit allait
chercher 500 Mo sur Internet. /etc/setops (0700 contre 0755) et /srv/restic au
site portaient le meme desaccord. test_repertoires_partages.py le refuse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:01:54 -04:00
20a5e44803 client_backup : le premier rapport a Icinga part d'un marqueur a lui ; le pare-feu ne compte que ses critiques
La copie de l'AC d'Icinga est deposee aussi par client_sante, plus tot :
sur une flotte neuve elle ne changeait jamais ici, et rien ne partait
(reconstruction de Chezlepro). client_backup retient desormais l'empreinte
de l'Icinga qui l'a entendu, apres le rapport. eprouver_parefeu ne s'arrete
plus sur les critiques presents avant l'activation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:08:55 -04:00
b135b09488 client_backup : un Icinga neuf recoit le premier rapport sans attendre dimanche
La copie de l'AC d'Icinga change quand Icinga ou le noeud est neuf : elle
declenche deposer, verifier le depot, verifier la restauration. Eprouve
sur web-frontal-01 de Technolibre ; second passage sans effet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:40:20 -04:00
515aac415a restauration : la section d'une base passe a psql par l'entree standard
postgres ne lit pas le repertoire jetable de root ; trouve en repetition
sur data-sql-01 de Technolibre. Le test l'exige desormais.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:51:19 -04:00
8a9da0c31a restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
f3e8883083 flux : sans voir son site, un ecosysteme qui en depend ne regenere pas ses pare-feux
Sur le runner d un locataire (ni underlay.yml ni plan du site), make flux reecrivait des
regles amputees de tout lien au site : AXFR du DNS public, collecte de la fabric,
insemination. Le generateur s abstient et le dit ; les regles committees font foi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:33:27 -04:00
e84b155a5f pool d adresses publiques : le site attribue a chaque locataire la sienne
Declare dans opnsense.yml du site, rendu par le contrat (ip_publique), valide (une par
locataire, jamais celle du site), compare aux alias du WAN par frontiere-plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:24:09 -04:00
712a7da1fd frontiere : les flux admin traduits chez les tenants ; edge retire de l Internet
Le devis OPNsense ne rendait le chemin du poste chez un tenant qu au travers des flux
externe ; il traduit desormais les flux admin (gestion, VPN). Applique : 4 retraits
(WAN -> edges), 18 ajouts, 0 ecart. sonde_tcp : une fermeture propre apres la requete
est une reponse de la destination ; la mesure de la frontiere est conforme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:05:23 -04:00
1493059271 edge ferme a l Internet ; le pare-feu Proxmox recoit les flux externe
L edge n expose qu a sa zone d administration (plus de pair externe) ; le public passera
par le web frontal. Le devis Proxmox recoit les flux externe depuis +t<i>-internet (RFC 1918
exclus en nomatch) et depuis l admin quand le poste en est client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:58:01 -04:00
1bd211d62b resolution_interne : entre machines du site, chaque nom mene a son service
L edge expose les interfaces web aux personnes ; les VM du site vont directement au
service. Declare par domaine (service | edge, defaut edge) ; plancher, zone et certificat
du service suivent. Pose au site : 35 planchers sur 35 conformes ; locataires inchanges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:25:37 -04:00
eee6851c3b sonde plancher ; une exposition sans port n est plus attribuee a l edge
La zone publie l empreinte de ce que le plancher doit porter ; chaque machine la compare
a son /etc/hosts. Au site, elle a revele que sauvegarde, pki et dns.genese.internal
pointaient vers l edge (regression de mon deploiement du matin) : la derivation ne donne
plus a l edge ce qui n a pas de port. Zone du site corrigee, SFTP des locataires verifie.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 12:34:47 -04:00
6b6a56ab3f sondes filtrage et edge : elles verifient le service rendu ; l edge refuse les noms inconnus
filtrage soumet GTUBE ; edge interroge chaque exposition en local. Sans serveur
par defaut, un nom inconnu recevait Keycloak : 000-defaut.conf (444, rejet TLS).
Garde test_sondes_syntaxe : chaque gabarit de sonde se rend en bash valide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 19:40:26 -04:00
b1c4775afe sauvegardes : un controle hebdomadaire de restauration, rapporte a Icinga
restic check en relisant 10 pourcent des donnees, puis restauration reelle du
dernier instantane avec --verify et comptage des fichiers. Service restauration,
fraicheur de 8 jours, filtre du compte d API complete.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 17:04:28 -04:00
0156596f01 P02 : une table du plan ne se coupe plus a son premier commentaire
_fusion_table traversait mal les commentaires interieurs a une entree :
chezlepro.ca (DNSSEC) etait coupee et ses enregistrements pris pour des entrees.
make verifier : CONFORME, 83 OK, 0 echec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:17:52 -04:00
f5adffb0de sondes conditionnelles : attendues seulement la ou elles sont posees
seulement_si dans meta/supervision.yml, lu par le gabarit Icinga des sondes ;
garde test_sondes_conditionnelles. journaux-frontiere ne rougit plus a vie chez
les locataires ; Technolibre sans critique.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:31:17 -04:00
185b000c60 icinga : un service passif qui n a jamais rien recu passe au rouge
Gabarit setops-rapport-attendu : actif, dummy critique, check_interval = le
ttl que le noeud envoie. Prouve a t+60 s sur site-mon-01, deploye sur les trois
Icinga ; la garde test_fraicheur_icinga lie seuils et ttl.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:05:15 -04:00
1d07a6cf80 runbooks : la recette tranche, le registre ne se compare plus a lui-meme
Un outil tiers veut n'offrir de ce moteur que ce qui n'agit pas. Le seul champ
qui le lui dise est `nature`. Il fallait donc qu'il ne mente pas, et il mentait
dans les deux sens.

`filiation` → `emancipation-prouver` se declarait « mesure » en portant
`fixes: {CONFIRMER: "true"}`. La cible tranche elle-meme — son refus dit
« cette preuve COUPE l'amont quelques secondes pour mesurer ». Un constat
rapporte ne rend pas inerte le geste qui l'obtient : l'etape passe a
`ecriture`.

Dans l'autre sens, trois cibles — flotte-creer, deployer-tout, reconstruire —
refusent sans confirmation sans que le registre le declare : un assistant les
lancait telles quelles, et sortait en 2. Comparer `nature` a `fixes` ne les
voyait pas, car c'est comparer deux champs ecrits par la meme main. `verifier`
lit desormais la RECETTE, qui ne ment pas.

Effet de bord traite : une etape qui agit barre celles qui la suivent dans la
console, alors qu'une « mesure » se debloque d'office. `depots-perimes` est
marque `facultative` — il nettoie ce que la filiation a laisse, il n'en est pas
le prealable.

`lister --json` rend le registre assemble d'un bloc, et le drapeau est refuse
hors de son action : rendre la prose humaine a qui demande du JSON est pire
qu'un refus. L'affichage humain ne bouge pas, et la preuve mesure ce qu'il
PORTE — un identifiant, un libelle, les marques de nature — et non seulement
qu'il n'est pas du JSON.

Valide : `verifier` a 0 ecart, test_runbooks.py 25/25, et sept des neuf
epreuves de `make test` ; test_raser et test_raser_resultat echouent sur
« Aucune instance montee », avant comme apres. Mesure : 127 etapes, dont 84 de
nature « mesure » — la surface qui n'agit pas.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RbXr5vv4Rat6PCPGG9GoG8
2026-09-25 17:54:03 -04:00
cd0f94a50b console : un tronc, deux branches — assembler deux fois est ce qui fait deriver
Il y avait deux assembleurs de charge, un par sorte de console. Ils ont derive deux fois le
meme jour : en forme (serveurs valait [] d'un cote et {} de l'autre, et charger() levait),
puis en contenu (cinq registres servis vides alors que le site a SON plan — 9 serveurs,
21 applications, 2 bases, 1 domaine, tous invisibles).

Console assemble, une seule fois, et fixe les clefs et leurs formes. Les branches ne
decident que de ce qui leur appartient : d'ou vient le plan, d'ou vient l'inventaire, quels
pouvoirs elles portent. ConsoleLocataire configure, ConsoleSite materialise et sert
desormais son propre plan, ConsolePoste herite du locataire et sait en plus sur quelle
fabric poser.

Le role et la portee ne se confondent pas : le role est une propriete de la classe, la
portee se calcule depuis les pouvoirs. Un poste prive de la voute du site reste l'atelier du
mainteneur et n'engendre pourtant rien. Le decoupage a montre un trou aussitot : ConsolePoste
heritait du refus d'un locataire — « elle ne sait pas sur quelle fabric poser » — alors qu'il
monte la carte ; ce qui lui manque est la voute, et accuser la mauvaise absence fait chercher
au mauvais endroit.

Le jugement des assistants remonte dans le tronc : il etait ecrit dans la route qui liste ET
dans celle qui execute, et celle qui se trompe est toujours celle qui execute.

Valide : make test a 0 echec, 8 tests de rendu sous node dont deux neufs, console lancee pour
de vrai (13 serveurs, 24 applications, 17 runbooks, 127 etapes, 0 ecart). make verifier a
aussi attrape une faute que j'avais laissee passer sur depots_perimes.yml — risky-shell-pipe,
corrige. P02 et P60 restent, et P60 demande une republication du wiki.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 21:55:49 -04:00
859ac07a54 console de site : un vide doit avoir la forme de ce qu'il remplace
La console du runner de SITE-Chezlepro ne montrait rien. Elle a douze machines.

inventaire_api sert serveurs en LISTE, inventaire_api_du_site le servait en TABLE. Les deux
sont vides et la page ne les lit pas pareil : (data.serveurs || []).map trouve {} — truthy,
sans .map — et charger() leve. La console d'un site mourait avant sa premiere vue, et le
message accusait une methode manquante plutot qu'une forme qui ment.

Et la vue regardait au mauvais endroit : le registre vide est voulu, mais la page en tirait
le message d'un locataire sans serveurs et les douze machines servies dans hotes n'etaient
dessinees nulle part. Une console de site dessine desormais SES machines, en lecture seule,
avec leur adresse, leur VMID, leurs roles et leur point de vie ; le panneau droit dit ce
qu'elle peut et renvoie aux Assistants.

C'est le defaut du 16 septembre par une autre porte : la premiere fois l'inventaire etait
vide et la page dessinait ce vide comme un plan vide ; cette fois il est plein et c'est la
vue qui regarde ailleurs.

Ce qui a trouve la cause n'est pas une lecture mais le BANC : en donnant pour la premiere
fois a test_rendu_gui la charge d'une console de site, il a leve sur charger(). Sans lui
j'aurais livre une vue juste par dessus un charger() qui leve.

Valide : node --check sur le bloc script, 7 tests de rendu dont deux neufs, make test a 0
echec, runbooks.py verifier a 0 ecart, P81 et P83 vertes. P02 reste en echec pour la raison
anterieure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 20:36:00 -04:00
4188cf5b6f la console mesure le pouvoir sur la voute, pas sur la carte
Le document des responsabilites attache chaque pouvoir a une voute : calculer n'en demande
aucune, configurer demande celle du tenant, materialiser celle du site. Le code lisait les
symlinks, c'est-a-dire les cartes. Le runner de Chezlepro-locataire montait la carte du
site sans en avoir jamais eu la voute : sa console se declarait poste et offrait 126 etapes
sur 126. Ces gestes seraient partis puis tombes sur un secret vide — un echec au milieu du
chemin, la ou un refus net aurait dit la verite avant de commencer.

contexte() derive desormais les pouvoirs des voutes presentes, et la portee decoule des
pouvoirs au lieu de les preceder. On ne prouve pas qu'une voute s'ouvre, le mot de passe se
tape a l'execution ; mais son absence est decisive et se mesure sans rien ouvrir. Lire une
carte reste permis : le pouvoir fabric suit toujours le symlink, consulter un miroir n'est
pas engendrer.

serveur_ops retire aussi le lien quand la fabric n'est plus declaree — il ne retirait rien,
et un runner gardait le pouvoir que son plan ne lui donnait plus. Il ne retire qu'un lien,
jamais un fichier : une vraie carte a cette place n'a pas ete ecrite par ce role, et il le
dit plutot que de detruire ce qui n'est pas le sien.

Valide : syntax-check et ansible-lint sur le role (profil production, 0/0), make test a 0
echec, P81 et P83 vertes. Six tests montent quatre faux disques et exigent la portee qui
leur revient, dont le defaut lui-meme : carte presente, voute absente, portee tenant.

Limite : P02 reste en echec pour la raison anterieure deja consignee.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 20:12:18 -04:00
d3a8124777 assistants : la portee se pese a l'etape, pas a la sequence
Mesure sur la console de TechnoLibre, portee tenant : 6 runbooks conduisibles sur 17, et
parmi les onze fermes, locataire-deployer et machine-une — c'est-a-dire le travail
quotidien d'un locataire. La cause : flotte-creer et creer-vm engendrent des VM et
exigent la fabric, et une portee declaree pour toute la sequence faisait basculer avec eux
des etapes voisines qui ne demandent que ce que le locataire possede deja.

Le runbook ne donne plus que le defaut ; l'etape qui exige davantage le declare. Le
locataire conduit sa sequence et bute precisement la ou il faut : sur la machine a
engendrer, pas sur le deploiement qui suit. La page ferme l'etape seule avec sa raison, et
la garde de la route lit la portee de l'etape visee par son index.

Un droit calcule sur l'ensemble se trompe toujours dans le meme sens : il refuse a
quelqu'un ce qu'il a le droit de faire, et le refus parait fonde puisqu'il nomme un vrai
manque. Il a fallu une console de locataire reelle pour le voir — sur le poste, qui porte
les deux liens, les dix-sept sequences s'affichaient conduisibles.

Valide : runbooks.py verifier a 0 ecart, make test a 0 echec (4 tests neufs, dont un qui
nomme le cas exact), P83 verte. P02 reste en echec pour la raison anterieure deja consignee.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 19:55:02 -04:00
f33b5be151 assistants : cent trente-deux cibles, et aucune ne disait dans quel ordre
La console offrait des boutons sans sequence. Rien n'y apprenait que site-creer precede
forge-amorcer, que le premier passage de site-deployer-tout s'arrete sur une forge vide
sans que ce soit un echec, ni que rien n'est pret avant valider : cet ordre vivait en
prose dans des documents que la console ne porte pas.

La vue Assistants conduit 17 runbooks et 126 etapes. Les 132 cibles documentees y sont,
chacune portee par un assistant ou exemptee avec son motif — une exemption muette est
refusee. Le registre ne recopie pas le Makefile : il declare l'ordre, la nature, la portee
et le pourquoi, et le libelle de chaque etape est lu dans le Makefile au moment de servir.

P83 est ecrite en meme temps que la liste, pas apres, parce qu'une liste qui suit une
autre prend du retard. Onze tests lui presentent des registres faux, un par forme de
retard, et exigent qu'elle les refuse.

Le navigateur ne nomme pas une commande, il nomme une place : la route lance ce que le
registre declare a cet index-la, avec les seules variables declarees. L'index compte, le
premier jour d'un site jouant site-deployer-tout deux fois. Une etape qui ecrit attend que
la precedente ait reussi ; une mesure reste toujours offerte, parce que mesurer apres un
echec est exactement ce qu'on fait ensuite.

Valide : runbooks.py verifier a 0 ecart, make test a 0 echec, les 83 preuves rejouees, et
la console lancee pour de vrai — 17 runbooks servis, six requetes malformees refusees une
a une, une etape de mesure executee de bout en bout avec son journal.

Limite, anterieure a ce travail : P02 (test_ecriture_plan) echoue sur domaines.yml, a
l'identique sur une copie de HEAD. Ajouter ou retirer un domaine public depuis la vue
Domaines leverait a l'enregistrement. Non corrige ici.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 16:31:16 -04:00
224ac2fe32 clonage : le plancher se perdait au troisieme maillon
instancier le derivait, le playbook savait le poser, et la table qui les relie
ne transmettait rien. Quatorze machines allaient naitre avec le ballooning
desactive sans qu une seule etape echoue : variable vide, extra-var non passee,
garde when: qui saute. Trois silences en file.

P75 lit la cible creer-vm, releve chaque $SETOPS_X qu elle consomme et exige
que la table qui les emet le declare. Eprouvee dans les deux sens.

74 OK, 0 echec, 1 saute.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-13 20:10:24 -04:00
2887b57f0c GUI : les six registres ont un formulaire genere, et la sauvegarde aussi
CHAMPS_ECRITS_A_LA_MAIN est vide. Serveurs et applications, les deux plus
gros, sont passes au generateur — chargement, rendu et sauvegarde.

L EPREUVE QUI COMPTE. Ouvrir chaque vue et enregistrer sans rien toucher
doit renvoyer exactement le plan qu on vient de lire : 14 serveurs, 25
applications, 2 domaines, 4 bases, IDENTIQUE partout. C est ce qui separe
un formulaire genere d un formulaire qui en a l air — un champ visible a
l ecran et perdu en silence a l enregistrement serait le pire des deux
mondes. test_rendu_gui.py le mesure a chaque make prouver.

TROIS DEFAUTS TROUVES EN CHEMIN.

Le formulaire annoncait des defauts INVENTES : 2048 Mo, 2 coeurs, 16G. Il
n existe aucun defaut fixe — deriver_ressources calcule depuis les roles
portes (1024 et 1 pour infra-pki-01, 5632 et 4 pour collab-01). Un repere
faux fait croire qu on connait la valeur. Le schema nomme le champ derive,
et l ecran montre la valeur reelle de cet hote. L option vide d un select
dit desormais ce qu elle produira : « (defaut : asgard) ».

Une SECONDE occurrence du defaut d hier dormait dans sourceDeValeurs :
elle lisait encore data.nomenclature. Elle n avait jamais leve parce que
la vue Serveurs, seule a emprunter cette source, avait un formulaire ecrit
a la main. Elle a leve a la seconde ou le generateur l a prise. Le banc ne
voit que les chemins vivants : verifier_gui.py fait donc aussi une
verification STATIQUE, qui voit ce qui dort.

La validation client s accrochait a data-v, pose a la main sur trois
champs. Le formulaire genere l aurait perdu et la validation serait passee
au vert sur ZERO champ. Le generateur marque chaque controle, et la
sauvegarde refuse si elle n en inspecte aucun.

DEUX CHAMPS GARDENT LEUR EDITEUR, et le schema le dit (x-editeur) : la
matrice des integrations montre les universelles et les exemptions, et
l editeur de liens contraint le role a meta/liens.yml. Le generateur s
efface plutot que de remplacer un editeur qui en sait plus que lui.

LIMITE : je n ai toujours pas ouvert ces pages dans un navigateur.

make prouver : CONFORME, 61 OK, 0 echec, 1 saute.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-08 18:26:33 -04:00
935a64a1bf plan : sauvegarder n emportait plus quarante lignes de commentaire
En voulant generer deux formulaires de plus, j ai trouve pire que ce que
je cherchais.

CE QUI ETAIT DEJA LA. Les quatre ecrivains de registre ecrasaient le
fichier au safe_dump. Mesure sur les fichiers reels : domaines.yml 6->3,
applications.yml 27->5, serveurs.yml 18->3. Quarante lignes, detruites
par n importe quel clic sur Sauvegarder dans les vues Serveurs,
Applications ou Domaines. Parmi elles, celle qui explique pourquoi
backup-01 a ete retire, et celle qui dit dans quel ordre les deux roles
du runner s appliquent. C etait l incident du 2026-08-18, jamais corrige
pour les registres du plan. Les quatre passent par _ecrire_registre :
aller-retour a vide identique a l octet, sur les quatre fichiers.

TROIS ECARTS DE SCHEMA, trouves en confrontant le schema aux VALIDATEURS
et non aux seuls plans :
 - edge designe un GROUPE, pas un hote. Le schema disait serveurs : un
   formulaire genere aurait offert une valeur qu aucun hote ne reconnait,
   donc aucun SAN, donc la panne du 2026-08-25 reintroduite ;
 - exposition, entierement valide par le moteur, manquait au schema ;
 - liens etait items: {type: object} — une liste d objets sans forme.
Et mail, offert par la vue Domaines depuis sa creation, decrit ici comme
un booleen, saisi la-bas comme du texte, lu par rien : retire.

P62 garde tout ca. Elle separe l entite du reste mecaniquement : un
validateur lit son entite par des variables LOCALES, les autres registres
par ses PARAMETRES. Controle negatif rejoue.

LES FORMULAIRES. Serveurs de BD et Domaines sont generes, chargement et
sauvegarde compris. Quatre registres sur six. Le generateur a appris la
liste d objets.

LIMITE : restent serveurs et applications, les deux plus gros ; et je n ai
toujours pas ouvert ces pages dans un navigateur.

make prouver : CONFORME, 61 OK, 0 echec, 1 saute (62 preuves).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-08 17:54:49 -04:00
88033f37b8 GUI : la vue Nomenclature, et deux fautes que mes bancs ne voyaient pas
Some checks are pending
verifier / verifier (push) Waiting to run
LA VUE. La nomenclature etait le seul registre que le GUI ne savait pas
ecrire du tout : ajouter une fonction exigeait d ouvrir le YAML. Elle a
sa vue, et son formulaire est GENERE depuis le schema. Deuxieme registre
sur six. couverture_gui verifier passe : les 28 champs des plans reels
sont editables.

Elle n est pas un registre comme les autres : elle decrit la REGLE dont
VMID, VLAN, adresse et passerelle se derivent. Chaque fonction montre ce
qu elle derive et les VM qui la portent ; l index est montre mais pas
editable, parce qu il est alloue par le site ; valider_nomenclature
refuse de retirer une fonction encore portee, ou de designer une zone
non declaree.

DEUX FAUTES, ET POURQUOI MES BANCS NE LES VOYAIENT PAS.

Le formulaire des bases, livre la veille, etait casse dans un navigateur.
Il lisait data.schema, or il n existe aucun data global : c est une const
locale de charger(). ReferenceError a l ouverture, et zone morte dans
sauvegarderBases. Je l avais eprouve sous node EN LUI PASSANT data : le
banc reproduisait la fonction, pas sa portee. D ou test_rendu_gui.py, qui
charge le JS entier dans un DOM simule et dessine les douze vues, avec son
controle negatif.

Le schema decrivait reservations comme une table de zones ; le fichier
reel est un bloc plat. P61 comparait des NOMS aplatis, donc ne voyait
rien. Elle compare desormais aussi la FORME.

ECRIRE SANS DEPLACER UN COMMENTAIRE. _fusion_chirurgicale remplace le
bloc entier des qu une valeur change : quinze entrees compactes devenaient
42 lignes, et le commentaire du poste d exploitation se retrouvait en tete
du bloc, ou il affirmait que collab etait le poste d exploitation. Un
commentaire deplace n est pas laid, il est faux. _fusion_table edite les
tables ligne a ligne ; le diff fait trois lignes.

Au passage : sort_keys triait le schema, donc l ordre des cases a l ecran
(reserve_max avant reserve_min) ; et _ecrire_index_nomenclature ecrivait
encore par write_text, oubliee au passage des ecritures atomiques.

LIMITE : deux registres sur six sont generes, et je n ai toujours pas
ouvert cette page dans un navigateur.

make prouver : CONFORME, 60 OK, 0 echec, 1 saute.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-08 17:08:45 -04:00
6077b179af plan : l ecriture des registres devient atomique — tout, ou rien
Some checks are pending
verifier / verifier (push) Waiting to run
`path.open("w")` TRONQUE avant d ecrire : entre les deux, le fichier est vide.
Une exception dans yaml.safe_dump, un disque plein, un Ctrl-C, et
instance/plan/serveurs.yml reste mutile.

L asymetrie fait la gravite : hosts.yml se regenere d un
make instancier-appliquer, le PLAN ne se regenere de rien. C est la source
unique de verite. Git est le filet, mais encore faut-il savoir qu on est tombe.

TREIZE SITES, UNE SEULE FONCTION

Le defaut n etait pas dans le GUI seul : douze sites dans sept fichiers, dont
les miroirs CLI des MEMES registres. Corriger le GUI seul aurait recree la
divergence que P41 garde depuis les neuf resolutions d instance. La fonction
vit donc dans inventory_rules.py, que les sept importaient deja. Une source,
pas douze.

TROIS DETAILS QUI FONT LA DIFFERENCE ENTRE « CA MARCHE » ET « CA TIENT »

  temporaire dans le MEME dossier   os.replace n est atomique qu au sein d un
                                    meme systeme de fichiers ; un /tmp sur une
                                    autre partition casserait la garantie sans
                                    rien dire
  fsync AVANT le rename             sinon le renommage peut atteindre le disque
                                    avant le contenu : au retour d une coupure
                                    brutale, un fichier neuf et VIDE — le defaut
                                    qu on ferme, deplace d un cran
  report des droits                 mkstemp cree en 0600, le plan est en 0664 et
                                    doit rester lisible par le groupe sur les
                                    runners

LE TEST PORTE SON PROPRE CONTROLE NEGATIF

scripts/tests/test_ecriture_atomique.py rejoue D ABORD l ancienne forme et
verifie qu elle DETRUIT. Sans ce controle, « le fichier est intact » ne
prouverait rien — il pourrait l etre parce que rien n a ete ecrit du tout. Une
garantie qu on n a jamais vue echouer n est pas une garantie, c est une
habitude.

Branche sur P02, dont le titre annoncait « inventory_host » alors qu il lance
maintenant trois tests. Corrige au passage.

LA VOUTE DU GUI : VERIFIEE, PAS DE DEFAUT

Le soupcon etait qu executer_flux pose ANSIBLE_VAULT_PASSWORD_FILE (un seul mot
de passe) alors que creer une VM ouvre DEUX voutes depuis « une voute, une cle ».

Eprouve contre deux voutes JETABLES a mots de passe distincts — jamais les
vraies. Les deux variables se CUMULENT : Ansible essaie tous les secrets, et un
PASSWORD_FILE errone n empeche rien. Confirme en sondant l environnement qu une
recette make recoit reellement : le mot de passe saisi ET les cinq cles
calculees par voutes.py.

Ce qui sauve ce chemin n est donc pas le mot de passe saisi, c est
l IDENTITY_LIST que make pose par-dessus. Chacun couvre ce que l autre ne
couvre pas — le PASSWORD_FILE sert le runner qui n a que sa cle, l IDENTITY_LIST
le poste qui les a toutes. Ecrit au-dessus du code, pour que personne ne
« simplifie » en retirant l un des deux.

make prouver : CONFORME, 59 OK, 0 echec, 1 saute.
make instancier : DIFF VIDE, quatre registres relus, droits 664 preserves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-08 14:57:57 -04:00
0595bf03c1 sonder : rapporter ce qui distingue, au lieu d un echec
Some checks are pending
verifier / verifier (push) Waiting to run
Trois faux diagnostics en une journee, tous dus a l instrument et aucun au
composant. curl et bash /dev/tcp ecrasent quatre causes incompatibles dans le meme
mot : ouvert, une POLITIQUE qui refuse, une machine ABSENTE, et la frontiere muette.

LE MEME CODE DIT DEUX CHOSES SELON LE DELAI, et c est la distinction qui a coute le
plus cher : EHOSTUNREACH immediat = pas de route ; le meme apres trois secondes =
il n y a pas de machine, c est l ARP qui renonce. Les confondre a fait appliquer un
pare-feu pour reparer un vide.  est pure, donc gardee par un test qui
exige que les deux ne se lisent jamais pareil.

LA GARDE ECHOUAIT DU COTE SILENCIEUX. L outil dit par quelle SOURCE le paquet part
et refuse de conclure sur une passerelle anycast — le piege qui m a fait declarer
muet un REJECT qui emettait bien ses RST. Ma premiere version rendait « pas
anycast » quand inventory_rules manquait, c est-a-dire sur un hyperviseur ou l on a
copie le seul fichier : precisement la ou le piege se produit. Une garde qui echoue
doit crier, pas se taire.

ET « NON CONCLUANT » EST UN RESULTAT : sur une source anycast et un silence, l outil
ne tranche pas, il dit quoi faire — compter les paquets du cote qui refuse, ou
sonder depuis une VM.

TCP seulement, et c est dit : UDP n a pas de poignee.

Valide contre le reel depuis ops-01 : trois cas sur quatre, le quatrieme attendant
deux machines vivantes dans un meme tenant.

make verifier : vert. make prouver : CONFORME, 53 OK, 0 echec, 0 saute.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-08-28 17:02:20 -04:00
ef832d11d6 insemination : la cle d'amorcage, bornee au meme groupe que le flux
Le flux etait declare et applique ; il manquait l'IDENTITE. Le runner du SITE
atteignait la porte de ops-01 sans avoir de cle.

LE PIEGE COMPTE PLUS QUE LE CORRECTIF. La cle s'injecte au CLONAGE, et `creer-vm`
cree TOUTES les machines d'un tenant. L'injecter a chaque clonage aurait donne a
l'hebergeur un acces SSH a la flotte entiere de chaque locataire, en silence — ca
aurait defait a la couche IDENTITE ce que le pare-feu venait de borner a la couche
RESEAU. Le meme critere gouverne donc les deux : porter `serveur_ops_tenant`.
`SETOPS_CLES_AMORCAGE` est vide partout ailleurs. Elle S'AJOUTE a celle de
l'exploitant, elle ne la remplace pas : c'est l'humain qui arme.

La cle vient du PLAN DU SITE, pas du disque local : materialiser depuis le poste
et depuis le runner doit produire la meme VM.

DEUX COUCHES MANGEAIENT LES ESPACES. Proxmox rendait `SSH public key validation
error` — message muet sur la cause. Isole par un CONTROLE (rejouer sans la cle :
la tache passe), puis par la mesure de ce qui arrivait au module :

    "sshkeys": "ssh-ed25519"     <- le premier mot, rien d'autre

J'ai accuse `make` d'abord ; c'etait `ansible-playbook -e cle=valeur`, qui decoupe
AU SHLEX. D'ou l'environnement pour le transport et `-e '{...}'` en JSON pour
l'entree. (Un scalaire YAML plie ne produit pas non plus de saut de ligne.)

TROIS TESTS QUI NE GARDAIENT RIEN. `test_inventory_host` inscrit ses tests dans une
liste explicite ; mes deux nouveaux n'y etaient pas — definis, jamais joues. La
garde d'exhaustivite ajoutee en a trouve un TROISIEME le jour meme,
`test_etiquette_vlan_repli_et_vide_explicite`, jamais inscrit depuis sa creation :
inscrit, il levait un KeyError sur une fixture qu'il lisait mal. Un test non
inscrit est pire qu'un test absent : on croit l'avoir.

PREUVE, AVEC SON CONTROLE NEGATIF :

    runner du SITE -> ops-01        ops-01  10.17.19.41/24   entre
    runner du SITE -> 10.17.19.21   Connection timed out     refuse

make verifier : vert. make prouver : CONFORME, 52 OK, 0 echec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-08-28 13:45:44 -04:00