Doc : passe complete (le depot dit ce qu'il fait)

- docs/plan-et-generation.md (nouveau) : guide central -- modele
  (entites + liens), registres et schemas, reference make/CLI et vues
  GUI, flux editer-le-plan -> instancier -> appliquer, garde-fous.
- AGENTS.md : section « Le plan et la generation de l'inventaire »
  (regle d'or : hosts.yml est genere, ne pas l'editer).
- README.md : section plan + remplacement du flux legacy
  hote-planifier/ajouter par le flux par le plan ; liste des registres.
- Rafraichissement architecture-set-ops.md, nomenclature-vm.md,
  catalogue-services.md ; terminologie domaine -> fonction dans la prose.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-06-23 22:46:48 -04:00
parent 4518e3e44e
commit 30e405dc92
7 changed files with 233 additions and 48 deletions

View file

@ -35,6 +35,24 @@ Conséquence pour le travail : préserver la discipline qui tient lensemble
---
## Le plan et la génération de linventaire (méta-classe)
`Set-OPS` se pilote par un **plan**, pas par lédition directe de linventaire.
Linventaire Ansible est **généré** depuis le plan.
**RÈGLE DOR : `inventories/production/hosts.yml` est un artefact GÉNÉRÉ. Ne jamais léditer à la main.** On édite le *plan*, puis on régénère.
- L**application** est lentité pivot ; le **groupe** Ansible nest quune capacité (le rôle appliqué), plus une cible de liaison.
- Le plan vit dans des registres machine-lisibles : `docs/serveurs.yml` (les VM), `docs/applications.yml` (les services et leurs liens `requiert`/`utilise`/`expose`), `docs/bases-donnees.yml`, `docs/domaines.yml`, `docs/nomenclature.yml`.
- Génération : `make instancier` (génère + diff sémantique), `make instancier-appliquer` (régénère `hosts.yml`, refuse si le diff nest pas vide — `FORCE=1` pour un changement intentionnel).
- Flux : **éditer le plan → `make instancier` (revoir le diff) → `make instancier-appliquer` → déployer**. Via le GUI : vues **Serveurs** et **Applications**, puis « Appliquer le plan » (la vue Inventaire est en lecture seule).
- VMID / IP / VLAN / passerelle sont **dérivés** de la `fonction` via la nomenclature ; les groupes dune VM sont dérivés (socle + services des applications + intégrations + état).
- Garde-fous : validateurs de registres, diff-vide, `node --check` du JS du GUI (`scripts/verifier_gui.py`, dans `make inventaire-verifier`), git comme filet.
Référence complète : **`docs/plan-et-generation.md`**.
---
## Règle dor IA
Un seul agent IA travaille dans ce dépôt à la fois.

View file

@ -2,6 +2,9 @@
## 2026-06-23
### Ajouté
- **Documentation — passe complète (le dépôt « dit ce qu'il fait »).** Nouveau guide central **`docs/plan-et-generation.md`** : le modèle (entités + liens), les registres et leurs schémas, la référence des commandes `make`/CLI et des vues GUI, le flux « éditer le plan → `instancier` → appliquer », les garde-fous. `AGENTS.md` gagne la section « Le plan et la génération de l'inventaire » (règle d'or : `hosts.yml` est généré, ne pas l'éditer). `README.md` : section « Le plan : on édite, l'inventaire se génère » + remplacement du flux legacy `hote-planifier`/`ajouter` par le flux par le plan. Rafraîchissement de `docs/architecture-set-ops.md` (entités du plan), `docs/nomenclature-vm.md` et `docs/catalogue-services.md` ; correction de la terminologie **domaine → fonction** dans la prose (collision avec le DNS levée jusque dans la doc).
### Modifié
- **Rework GUI : l'UI édite le plan (branche `bascule-inventaire-genere`).** La vue **Serveurs** devient éditable (fonction / état / placement Proxmox / intégrations `clients_*`, avec VMID/IP/VLAN dérivés en direct), avec « + Serveur », « Sauvegarder les serveurs » (`POST /api/serveurs`) et **« Appliquer le plan → hosts.yml »** (`POST /api/instancier` → `instancier appliquer`). La vue **Inventaire** passe en **lecture seule** : bandeau explicite + l'écriture directe (`POST /api/inventaire`) est refusée (409) puisque `hosts.yml` est désormais généré. Tout passe par le plan (`serveurs.yml` / `applications.yml`) puis « Appliquer ». Garde-fou JS `node --check` exécuté à chaque étape.
- **Bascule méta-classe (branche `bascule-inventaire-genere`).** `make instancier-appliquer` régénère `inventories/production/hosts.yml` **depuis le plan** (refuse si le diff n'est pas vide, sauf `FORCE=1` pour un changement intentionnel ; git sert de filet). Effectuée avec diff vide vérifié : `hosts.yml` est désormais un artefact généré, sémantiquement identique à l'ancien (vérifié par `make inventaire-verifier` complet + chargement GUI). À ce stade le GUI édite encore `hosts.yml` directement (rework à venir) : éditer le **plan** (`serveurs.yml`/`applications.yml`) puis `make instancier-appliquer`.

View file

@ -4,7 +4,7 @@ Dépôt Ansible central pour construire, configurer, maintenir et documenter les
## Mission
`Set-OPS` ne se limite plus à l'exploitation : il **définit et construit l'écosystème numérique souverain de Chezlepro Inc.** — une infrastructure interne auto-suffisante, sans dépendance SaaS, décrite en code et pilotée par des registres machine-lisibles qui font office de **source unique de vérité** (`docs/nomenclature.yml`, `docs/dependances-groupes.yml`, `docs/bases-donnees.yml`).
`Set-OPS` ne se limite plus à l'exploitation : il **définit et construit l'écosystème numérique souverain de Chezlepro Inc.** — une infrastructure interne auto-suffisante, sans dépendance SaaS, décrite en code et pilotée par des registres machine-lisibles qui font office de **source unique de vérité** (`docs/serveurs.yml`, `docs/applications.yml`, `docs/bases-donnees.yml`, `docs/domaines.yml`, `docs/nomenclature.yml`, `docs/dependances-groupes.yml`).
Piliers de l'écosystème :
@ -20,6 +20,21 @@ L'état voulu est **déclaratif et convergent** (appliqué par les groupes Ansib
Cadre et règles d'autorité : voir `AGENTS.md` (section « Mission et identité »).
## Le plan : on édite, l'inventaire se génère
`Set-OPS` se pilote par un **plan**, pas par l'édition directe de l'inventaire.
`inventories/production/hosts.yml` est **généré** depuis le plan — **ne pas l'éditer à la main**.
```
éditer le PLAN → make instancier (revoir le diff) → make instancier-appliquer → make deployer
```
- **Plan** : `docs/serveurs.yml` (les VM), `docs/applications.yml` (les services et leurs liens), `docs/bases-donnees.yml`, `docs/domaines.yml`, dérivés via `docs/nomenclature.yml`.
- **GUI** (`make inventaire-ui`) : vues **Serveurs** et **Applications** pour éditer, puis « Appliquer le plan » ; la vue **Inventaire** est en lecture seule.
- VMID / IP / VLAN sont **dérivés** de la `fonction` ; les groupes d'une VM sont dérivés des applications qui y tournent.
Guide complet : **`docs/plan-et-generation.md`**.
## Portée transverse
Au-delà des piliers ci-dessus, le dépôt couvre des préoccupations transverses, communes à toutes les VM :
@ -81,18 +96,18 @@ Ouvrir l'interface locale de gestion d'inventaire :
make inventaire-ui
```
Planifier une VM sans la créer ni la déployer :
Planifier une VM passe désormais par le **plan**, pas par l'édition de l'inventaire :
1. déclarer la VM dans `docs/serveurs.yml` (vue **Serveurs** du GUI, ou `make serveurs`) — `fonction`, `etat`, placement ; VMID/IP/VLAN sont dérivés ;
2. déclarer les services qui y tournent dans `docs/applications.yml` (vue **Applications**) ;
3. régénérer l'inventaire :
```bash
make hote-planifier HOTE=obs-01 VMID=94101 GROUPES="serveurs_debian serveurs_durcis serveurs_prometheus serveurs_loki"
make instancier # génère + diff sémantique (que va-t-il changer ?)
make instancier-appliquer # régénère inventories/production/hosts.yml
```
Ajouter une VM à l'inventaire production et l'associer aux groupes qui détermineront sa configuration :
```bash
make hote-ajouter HOTE=web-frontal-01 VMID=95301 ADRESSE_IP=10.1.15.31 GROUPES="serveurs_debian serveurs_durcis"
make hote-groupes HOTE=web-frontal-01 GROUPES="serveurs_debian serveurs_durcis"
```
Les anciennes commandes `make hote-planifier` / `hote-ajouter` / `hote-groupes` éditaient l'inventaire **directement** ; elles sont **supplantées** par le plan (l'inventaire est généré, ne pas l'éditer à la main).
Chaque groupe opérationnel doit avoir son playbook homonyme dans `playbooks/groupes/`.

View file

@ -1,22 +1,25 @@
# Architecture Set-OPS
Set-OPS est un dépôt global d'exploitation.
Set-OPS définit et construit l'écosystème numérique souverain de Chezlepro. Il se
pilote par un **plan** : l'inventaire Ansible (`inventories/production/hosts.yml`)
est **généré** depuis le plan, pas édité à la main.
## Domaines
- Modèle, registres, commandes et flux de travail : **`docs/plan-et-generation.md`**.
- Règles d'autorité : **`AGENTS.md`** (sections « Mission et identité » et « Le plan et la génération de l'inventaire »).
## Entités du plan
```text
socle : socle commun Debian
durcissement : sécurité
maintenance : mises à jour
monitoring : supervision
proxmox : hyperviseurs
modeles_vm : modèles de VM
web : services web
database : bases de données
backup : sauvegardes
applications : services applicatifs
serveur (VM) docs/serveurs.yml fonction, état, placement, intégrations
application docs/applications.yml groupe (rôle), hôte, port, requiert, expose
base docs/bases-donnees.yml serveur de BD, base, propriétaire, secret (Vault), portée
domaine (DNS) docs/domaines.yml zone publique, autorité, edge
nomenclature docs/nomenclature.yml fonctions -> VMID / VLAN / IP (dérivés)
```
L'**application** est l'entité pivot ; le **groupe** Ansible n'est qu'une capacité
(le rôle appliqué). VMID / IP / VLAN et les appartenances de groupes sont **dérivés**.
## Rôles Ansible
Les rôles actifs sont conservés directement sous `roles/`.

View file

@ -12,7 +12,9 @@ Les playbooks ajoutés maintenant sont des points d'ancrage. Ils ne doivent pas
La nomenclature des VM et des VMID est documentée dans `docs/nomenclature-vm.md`.
Un service central peut partager un hôte avec d'autres services du même domaine opérationnel. La relation stricte est entre groupe et playbook, pas entre groupe et VM.
Un service central peut partager un hôte avec d'autres services de la même fonction opérationnelle (plusieurs applications par VM). La relation stricte est entre groupe et playbook, pas entre groupe et VM.
> Modèle à jour : chaque service est une **application** (`docs/applications.yml`). Voir `docs/plan-et-generation.md`.
## Services centraux

View file

@ -1,15 +1,15 @@
# Nomenclature des VM
La nomenclature doit rendre lisible le domaine opérationnel d'une VM sans l'enfermer dans un seul service.
La nomenclature doit rendre lisible la fonction opérationnelle d'une VM sans l'enfermer dans un seul service. (« fonction » est le terme du plan ; « domaine » est réservé au DNS.)
Un hôte peut porter plusieurs groupes Ansible. Le nom de VM doit donc représenter une capacité ou un domaine, pas forcément un produit unique.
Un hôte peut porter plusieurs groupes Ansible et plusieurs applications. Le nom de VM représente donc une capacité ou une fonction, pas forcément un produit unique.
## Noms de VM
Format recommandé :
```text
<domaine>-<numero>
<fonction>-<NN>
```
Exemples :
@ -29,7 +29,7 @@ web-frontal-01
web-dorsal-01
```
La couche applicative web suit le même format. Le tier est porté par le domaine, au singulier puisqu'il nomme une instance :
La couche applicative web suit le même format. Le tier est porté par la fonction, au singulier puisqu'il nomme une instance :
```text
web-frontal-01 présentation web (UI, rendu, assets), groupe serveurs_web_frontaux
@ -83,10 +83,10 @@ Réseau interne unique : `10.1.0.0/16`. Segmentation par fonction, un `/24` et u
Adresse d'hôte (4ᵉ octet) : **`service × 10 + NN`**. `.1` = passerelle ; `.2``.9` réservés. Exemple : `web-dorsal-01` (catégorie 5, service 4, NN 01) → `10.1.15.41`.
Tout se dérive du domaine de l'hôte, et la source unique machine-lisible est **`docs/nomenclature.yml`** :
Tout se dérive de la fonction de l'hôte, et la source unique machine-lisible est **`docs/nomenclature.yml`** :
```text
hostname = <domaine>-<NN>
hostname = <fonction>-<NN>
VMID = 9 · catégorie · service · NN
VLAN = catégorie.vlan
IP = 10.1.<vlan>.(service × 10 + NN)
@ -94,13 +94,13 @@ IP = 10.1.<vlan>.(service × 10 + NN)
`make inventaire-ui` lit ce registre et **propose** automatiquement VMID, VLAN, IP et passerelle quand on nomme un hôte. La sécurité entre zones se fera par règles inter-zones (nftables / edge), pas par l'adressage.
Contrainte : `NN` de 01 à 09 par domaine (l'octet hôte reste dans le bloc du service). Au-delà, ouvrir un nouveau domaine/service dans `docs/nomenclature.yml`.
Contrainte : `NN` de 01 à 09 par fonction (l'octet hôte reste dans le bloc du service). Au-delà, ouvrir une nouvelle fonction/service dans `docs/nomenclature.yml`.
La segmentation `10.1.0.0/16` remplace l'ancienne plage d'essais `192.168.12.x`.
## Variables de provisioning d'hôte
L'inventaire est la source de vérité du provisioning d'une VM. Ces variables d'hôte sont saisissables via `make inventaire-ui` (ou à la main) et décrivent l'instanciation attendue :
Le **plan** est la source de vérité du provisioning. Le placement et le dimensionnement d'une VM vivent dans `docs/serveurs.yml` (vue **Serveurs** du GUI) ; VMID / IP / VLAN / passerelle sont **dérivés** de la fonction. Ces variables d'hôte sont alors **générées** dans l'inventaire (ne pas les éditer à la main) :
| Variable | Sens | Type |
| --- | --- | --- |
@ -117,30 +117,22 @@ L'inventaire est la source de vérité du provisioning d'une VM. Ces variables d
| `proxmox_memoire` | mémoire en Mo | int |
| `proxmox_coeurs` | nombre de cœurs | int |
Ces valeurs sont renseignées dans l'inventaire ; leur consommation automatique par `make creer-vm` (au lieu des arguments en ligne de commande) est l'étape d'intégration suivante. Une valeur vide n'est pas écrite, pour garder l'inventaire propre.
Ces valeurs sont **générées** dans l'inventaire depuis `docs/serveurs.yml` + la nomenclature (`make instancier-appliquer`). Une valeur vide n'est pas écrite, pour garder l'inventaire propre.
## Hôtes planifiés
## État d'un hôte (planifié / actif)
Les hôtes prévus mais non encore déployés sont placés dans `hotes_planifies`.
Chaque VM porte un `etat` dans `docs/serveurs.yml` :
Les hôtes réellement joignables par Ansible sont placés dans `hotes_actifs`.
- `planifie` — prévue mais non encore déployée → groupe `hotes_planifies` à la génération ;
- `actif` — réellement joignable par Ansible → groupe `hotes_actifs`.
Planifier un hôte :
L'état se change dans la vue **Serveurs** du GUI (ou `docs/serveurs.yml`), puis on
régénère l'inventaire :
```bash
make hote-planifier HOTE=obs-01 VMID=94101 GROUPES="serveurs_debian serveurs_durcis serveurs_prometheus serveurs_loki"
make instancier-appliquer
```
Activer un hôte existant ou déjà cloné :
Les déploiements groupés limitent automatiquement l'exécution à `<groupe demandé> & hotes_actifs`, ce qui permet de décrire l'écosystème complet (hôtes planifiés inclus) sans tenter de configurer une VM qui n'existe pas encore.
```bash
make hote-ajouter HOTE=obs-01 VMID=94101 ADRESSE_IP=192.168.12.141 GROUPES="serveurs_debian serveurs_durcis serveurs_prometheus serveurs_loki"
```
Les déploiements groupés limitent automatiquement l'exécution à :
```text
<groupe demandé> & hotes_actifs
```
Cela permet de renseigner l'inventaire complet sans tenter de configurer une VM qui n'existe pas encore.
> Les anciennes commandes `make hote-planifier` / `hote-ajouter` éditaient `hosts.yml` directement ; l'inventaire étant désormais **généré**, elles sont supplantées par le plan (`docs/serveurs.yml`).

152
docs/plan-et-generation.md Normal file
View file

@ -0,0 +1,152 @@
# Le plan et la génération d'inventaire (méta-classe)
Set-OPS ne s'édite plus comme un inventaire à la main : on **décrit un plan**, et
l'inventaire Ansible en est **généré**. Le dépôt est la définition ; chaque VM en
est une instance. Ce document décrit le modèle, les registres, les commandes et
le flux de travail.
> Règle d'or : **`inventories/production/hosts.yml` est GÉNÉRÉ. Ne jamais l'éditer
> à la main.** On édite le *plan* puis on régénère (`make instancier-appliquer`).
---
## 1. Le modèle : deux ancres, cinq liens
L'écosystème = des **serveurs** (VM) et des **applications**, reliés à leurs
**bases**, leurs **domaines** et leurs dépendances :
```
serveur (VM) ──fournit──▶ capacités (= groupes/rôles Ansible)
application ──tourne_sur──▶ serveur (une VM peut porter N applications)
application ──requiert──▶ application(s) (DNS, PKI, BD…)
application ──utilise──▶ base(s) (via le DSN)
application ──expose──▶ domaine(s) public(s) (le FQDN, derrière l'edge)
base ──hébergée_sur──▶ serveur de BD
```
L'**application** est l'entité pivot : tout ce qui décrit « ce qui tourne et à
quoi c'est connecté » pend d'elle. Le **groupe** Ansible n'est plus une cible de
liaison — seulement une **capacité** qu'une VM fournit (le rôle appliqué).
---
## 2. Les registres (source unique de vérité)
Tous sous `docs/`, machine-lisibles, validés, consommés par le GUI, le CLI et Ansible.
| Registre | Décrit | Champs clés |
| --- | --- | --- |
| `nomenclature.yml` | nommage & adressage | `fonctions` (catégorie/service), `categories` (VLAN/sous-réseau/passerelle), `supernet` |
| `serveurs.yml` | les VM du plan | `fonction`, `etat` (actif/planifie), placement Proxmox (`noeud`/`stockage`/`disque`/`memoire`/`coeurs`), `integrations` (les `clients_*`) |
| `applications.yml` | les applications | `groupe` (capacité/rôle), `hote` (VM), `port`, `requiert`, `expose`, (+ bases via consommateur) |
| `bases-donnees.yml` | serveurs de BD + bases | `serveurs_bd` ; `bases_donnees` : `serveur`/`base`/`proprietaire`/`secret`(Vault), `consommateur` + `portee` (`application`/`groupe`/`hote`), `usage` |
| `domaines.yml` | zones DNS publiques | `domaines_publics` : `autorite`, `edge`, `secondaires`, `dnssec`, `mail` |
| `dependances-groupes.yml` | prérequis entre groupes | `requiert_groupes_actifs` |
### Dérivations clés
- **Nommage/adressage** : tout part de la `fonction` de l'hôte (`web-frontal-03`).
`VMID = 9·catégorie·service·NN`, `VLAN = catégorie.vlan`,
`IP = 10.1.<vlan>.(service×10 + NN)`. Voir `docs/nomenclature-vm.md`.
- **DSN** (lien application↔base) : `<type>://<proprietaire>:<secret>@<hôte>:<port>/<base>`.
Une application reçoit les bases où `(portee=application ET consommateur=elle)`
OU `(portee=groupe ET consommateur=son groupe)` OU `(portee=hote ET consommateur=son hôte)`.
- **Exposition DNS** : `application.expose: [fqdn]` + l'`edge` du domaine parent →
`serveurs_nginx` génère le vhost (`application → hôte → IP:port`).
---
## 3. La génération (méta-classe)
`make instancier` produit `hosts.yml` **depuis le plan** :
- **host vars** : `ansible_host`/`ansible_user` + `proxmox_*` (IP/VMID/VLAN/passerelle
**dérivés** de la nomenclature ; placement/taille depuis `serveurs.yml`).
- **groupes** d'une VM = socle (`serveurs_debian` + `serveurs_durcis`)
+ **services** (les `groupe` des applications de l'hôte)
+ **intégrations** (`serveurs.yml: integrations`)
+ **état** (`hotes_actifs` / `hotes_planifies`).
La comparaison est **sémantique** (via `ansible-inventory --list`, formatage
ignoré). « **Diff vide** » = le plan reproduit exactement l'inventaire courant ;
c'est le feu vert pour appliquer.
---
## 4. Le flux de travail
```
éditer le PLAN ──▶ make instancier (revoir le diff) ──▶ make instancier-appliquer ──▶ déployer
(GUI ou CLI) (que va-t-il changer ?) (régénère hosts.yml) (make deployer)
```
### Via le GUI — `make inventaire-ui`
Cinq vues :
| Vue | Rôle |
| --- | --- |
| **Inventaire** | **lecture seule** (inventaire généré) — vue d'ensemble des hôtes |
| **Serveurs** | éditer les VM du plan : fonction/état/placement/intégrations (VMID·IP·VLAN dérivés en direct) ; bouton **« Appliquer le plan »** |
| **Chaîne** | vue holistique par hôte : groupes → rôles, et par application ses `expose` / `requiert` / bases (DSN) |
| **Applications** | éditer les applications : groupe/hôte/port/requiert/expose |
| **Bases** | éditer serveurs de BD et bases (portée + consommateur), DSN affiché |
Édition → **Sauvegarder** (écrit le registre) → **Appliquer le plan** (régénère
`hosts.yml`). L'écriture directe de l'inventaire est refusée (409).
### Via le CLI / `make`
Chaque registre a son script miroir et ses cibles `make` :
| Domaine | Lister | Vérifier | Bootstrap (depuis l'inventaire) |
| --- | --- | --- | --- |
| Serveurs | `make serveurs` | `make serveurs-verifier` | `make serveurs-bootstrap` |
| Applications | `make applications` | `make applications-verifier` | `make applications-bootstrap` |
| Bases | `make bases` | `make bases-verifier` | — |
| Domaines | `make domaines` | `make domaines-verifier` | — |
Génération :
```bash
make instancier # génère hosts.genere.yml (gitignoré) + diff sémantique
make instancier-appliquer # régénère hosts.yml (refuse si diff non vide ; FORCE=1 pour forcer)
```
Validation globale : `make inventaire-verifier` (ansible-inventory + tous les
registres + **`node --check` du JS du GUI**).
---
## 5. Garde-fous
- **Validateurs** : chaque registre est validé (références connues, énumérations,
unicité). Un `expose` sans domaine parent, un `requiert` fantôme, une `portee`
inconnue, une `fonction` absente → rejet.
- **Diff vide** : `instancier-appliquer` refuse d'écraser l'inventaire si le plan
ne le reproduit pas (sauf `FORCE=1` pour un changement intentionnel).
- **`node --check`** : le JS embarqué du GUI est vérifié (`scripts/verifier_gui.py`,
intégré à `make inventaire-verifier`) — une erreur de syntaxe JS casse toute la page.
- **git** : `hosts.yml` est versionné ; `git diff` / `git checkout` est le filet.
- **Secrets** : jamais en clair ; `secret:` nomme une variable Ansible Vault.
---
## 6. Réutilisation de la règle (Ansible)
La règle de résolution vit **une seule fois**, en Python (`scripts/inventory_rules.py`),
et est exposée à Ansible par un *filter plugin* (`filter_plugins/registres.py`) :
`bases_de_application`, `applications_de_hote`, `expositions_des_applications`,
`chaine_connexion`. Les playbooks par application (`serveurs_web_dorsaux`/`_frontaux`)
itèrent ainsi sur les applications de l'hôte et résolvent leurs DSN.
---
## 7. Amorçage / reconstruction
Pour (re)construire le plan depuis un inventaire existant :
```bash
make serveurs-bootstrap # VM -> docs/serveurs.yml (fonction/état/placement/integrations)
make applications-bootstrap # services serveurs_* (hors socle) -> docs/applications.yml
make instancier # vérifier le diff vide
```
C'est ainsi que le plan a été initialisé sans perte, avec diff vide vérifié.