# CHANGELOG — Set-OPS ## 2026-07-29 — dette documentaire soldée (un README par rôle) + carte revue ### Ajouté — les 12 README de rôles manquants **Tous les rôles ont désormais un README.** Les 12 restants sont écrits, au format maison (intention → rôle → variables → notes/limites → prérequis), et documentent surtout ce qui ne se lit pas dans les tâches : - **Socle et résolution** — `serveur_debian` (rôle-catégorie sans tâches : il ne porte que le flux SSH du plan de gestion, *sans quoi les nftables couperaient l'accès Ansible*), `hosts_statiques` (le plancher `/etc/hosts` qui rend l'ordre de reconstruction possible). - **Rôles utilitaires** — `resoudre_base` et `resoudre_annuaire` : entrées/sorties (facts), et *pourquoi* le FQDN plutôt que le nom court (fédération + `verify-full`). - **Courriel** — `serveur_dovecot` (les trois réglages Dovecot 2.4 qui conditionnent la remise ; le local-part seul comme chemin commun LMTP/IMAP), `serveur_postfix` (liens `mailstore`/`milter`, recopie de `/etc/hosts` dans le chroot), `serveur_rspamd` (clé DKIM idempotente ; le domaine signé doit être **public** en prod). - **Sauvegardes** — `client_backup` (jobs déclaratifs, chiffrement côté client, *le dépôt neuf est vide tant qu'une première sauvegarde n'a pas tourné*) et `serveur_backup` (hors-nœud ≠ hors-site). - **SSO et supervision** — `serveur_oauth2_proxy` (le patron réutilisable Keycloak-devant- n'importe-quoi ; pourquoi `allow_unverified_email` est nécessaire avec un annuaire LDAP) et `serveur_icingaweb2` (modes `ldap` vs `external`, et l'écoute à restreindre en SSO). - **`client_unbound`** — le garde-fou de bascule du résolveur (`apply` **et** `confirm`, validation avant de toucher `/etc/resolv.conf`). ### Corrigé — `docs/carte-set-ops.md` ne décrivait plus l'état du code - **`expose` est consommé au déploiement** (la carte l'annonçait encore comme « Phase 3 à venir ») : vhosts nginx dérivés via `expositions_des_applications` + `expositions.conf.j2`, alias `/etc/hosts`, SANs d'edge dérivés par `instancier.py`. - **Trois mécanismes transverses ajoutés au catalogue** : résolution d'annuaire (`resoudre_annuaire`), plancher de résolution (`hosts_statiques`), et `resoudre_base` nommé dans la ligne des bindings app→base. - **Cinq entrées d'index ajoutées** : réseau/pare-feu, ordre de déploiement, preuve/recette, exploitation courante, wiki — des pans entiers du corpus n'étaient pas indexés. - Reste ouvert, explicitement : `meta/liens.yml` sur le seul `serveur_postfix`, et `requiert` non consommé au déploiement (indice applicatif ; l'ordre, lui, vient des couches+graphe). Validation : `make verifier` vert (ansible-lint 514 fichiers, tests, syntax-check, **23 preuves CONFORME**). ## 2026-07-28 — figures annotées dans le wiki (console d'exploitation) ### Ajouté — les 8 vues de la console illustrées, dans le wiki La série des figures annotées (une par vue du GUI, en **SVG auto-contenu** : capture + repères intégrés en base64) est désormais **intégrée** à l'unité wiki [`Le GUI (console d'exploitation)`](wiki/Le-GUI-console-d-exploitation.md), en fin de section ②. Vues éditables (Serveurs, Applications, Bases × 2, Domaines) puis dérivées (Flux, Couches, Réseau). - **Symlink `wiki/img → ../docs/img`** — foyer unique des figures dans `docs/img/` ; les pages wiki y réfèrent en relatif (`img/*.svg`) sans duplication dans l'arbre source. - **`make wiki-publier`** embarque désormais les `docs/img/*-annote.svg` (déréférencés) dans le wiki Forgejo publié — c'étaient jusqu'ici les seules `.md` qui voyageaient, donc aucune image. ## 2026-07-24 — underlay (fabric physique, cluster-global) ### Ajouté — l'underlay comme concept de premier plan Le modèle dérive l'adressage **par tenant** (VLAN `1000+index×10+zone`), mais la **fabric physique** qui porte la flotte — mgmt des switches, mgmt Proxmox/OOB, iSCSI, Ceph — n'appartient à aucun tenant et ne dérive d'aucun `index`. Elle vit dans le *sous-sol* du modèle. Jusqu'ici elle n'était pas codifiée. Elle l'est. - **`scripts/underlay.py`** + **`make underlay`** — charge/affiche/**valide** `underlay.yml` : réseaux (nom, VLAN, sous-réseau, passerelle optionnelle → SVI, MTU/jumbo) et hôtes fixes documentés (les switches). La validation refuse toute **collision avec la plage tenant** : VLAN < 1000, sous-réseaux hors des supernets `10.(10+index).0.0/16`. - **`underlay.yml`** (racine du moteur, **gitignore** comme le vault ; gabarit public `underlay.yml.example`), surchargeable par `SETOPS_UNDERLAY`. Absent → tout reste inchangé. - **`make devis-reseau`** émet désormais une **section 0. Underlay** (VLANs, SVI, hints jumbo, IP des switches en commentaire) et ajoute les VLAN underlay au **trunk** Proxmox, avant les tenants. Respecte le dialecte (`cisco`/`binardat`). - **Preuve P23** — `underlay.py --verifier` : la fabric n'empiète pas sur la plage tenant. **Sautée** (⚪) si `underlay.yml` est absent (dépôt public), comme P16 sans vault. Le plafond tenant (245) est inchangé : l'underlay occupe `10.0.0.0/16 .. 10.10.0.0/16`, laissé libre par la dérivation (index ≥ 1 → `10.11+`). ## 2026-07-23 (suite 7) ### Ajouté — dialecte de CLI du commutateur (`devis-reseau`) Constat de l'opérateur : son switch est un **Binardat**, dont la CLI diffère de Cisco sur deux points que le devis généré ignorait — et deux pièges qui font passer un VLAN mais fuir un tenant : - **Masque d'ACL** — Cisco veut un masque **inversé** (wildcard `0.0.255.255`), Binardat un masque **normal** (`255.255.0.0`). Le SVI (`ip address … 255.255.255.0`) était déjà normal, donc valide sur les deux. - **`remark`** — Binardat n'a pas la commande de commentaire d'ACL de Cisco. Ces lignes faisaient rejeter le bloc. **`scripts/devis_reseau.py`** gagne un **dialecte** (`cisco` par défaut, `binardat`) : `masque_acl()` choisit wildcard ou masque normal ; `remarque()` omet les `remark` en Binardat. Réglable par `--dialecte`, par `SETOPS_DIALECTE`, ou `make devis-reseau DIALECTE=binardat`. Le GUI (lecture seule) suit l'env. Le code public reste **générique** (défaut `cisco`). ## 2026-07-23 (suite 6) ### Ajouté — plan de recette (le pendant manuel de `make prouver`) Constat de l'opérateur : les 78 exercices « ④ À toi de jouer » du wiki forment, ensemble, un **plan de tests d'acceptation**. Formalisé, sans dupliquer : - **`scripts/plan_recette.py`** + **`make plan-recette`** — **génère** `docs/audit/plan-de-recette.md` depuis les exercices du wiki : une grille auto-contenue (le geste inline) par unité, colonnes *Ce qu'on éprouve · Le geste · Type (observe/casse-répare) · **Preuve auto***. La dernière colonne est extraite du texte (le `Pxx` que l'exercice mentionne) : elle montre quels gestes manuels sont **aussi** gardés par la machine. Étant générée, la grille **ne peut pas dériver** du wiki. - **Preuve P22** — `plan_recette.py --verifier` échoue si le fichier committé n'est plus à jour (le wiki a changé sans régénérer). Le plan de recette devient un artefact **auto-gardé**. - **Honnêteté de couverture** assumée dans le document : un « — » = **manuel seul** (aucune preuve machine ne le double) ; le plan ne prétend pas à l'exhaustivité au-delà des exercices du wiki. C'est le **pendant humain** de `make prouver` : le harnais prouve le *moteur* (P01–P21), la recette valide l'*exploitation* — et sert de checklist au `protocole-operateur-independant.md` (« exploitable sans IA »). Validé : 78 gestes sur 19 unités, 5 doublés d'une preuve `Pxx` ; P22 testée (détecte une dérive) ; `make verifier` → **CONFORME 22/22** (contre une instance cohérente). ## 2026-07-23 (suite 5) ### Ajouté — wiki : l'axe « méthode » (KB enrichie) Le wiki enseignait les fondamentaux *services* (identité, PKI, courriel…) mais pas la *méthode* de Set-OPS. Cinq pages ajoutées, au moule à 4 temps (concept → Set-OPS → transférable → à toi de jouer), avec exercices concrets : - **Le plan & l'adressage dérivé** — un seed (`index`), tout en découle (DRY, source unique). - **Multi-instance & fédération** — un moteur, N écosystèmes ; découverte par convention. - **La preuve** — « ne jamais affirmer plus que ce qu'on prouve » ; le registre, `make prouver`, P01–P21. - **Le GUI (console d'exploitation)** — éditer la source, dry-run avant apply, l'invalide impossible à saisir (le `