From 346a6a519209279c672dfeeeb8b5d06db0557e80 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Sat, 4 Jul 2026 11:39:40 -0400 Subject: [PATCH] =?UTF-8?q?docs(bindings)=20:=20taxonomie=20des=20liaisons?= =?UTF-8?q?=20(niveau=20=C3=97=20modalit=C3=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §11 : liaison = concept-chapeau. Axe niveau (liens app / intégrations nœud). Axe modalité orthogonal : requise (constitutive, doit échouer si absente) vs optionnelle (élective, opt-in). Le requis est déjà appliqué implicitement ; raffinement = le rendre explicite (requis: true|false, fail-fast). Co-Authored-By: Claude Opus 4.8 --- docs/bindings-conception.md | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/bindings-conception.md b/docs/bindings-conception.md index 19b0686..a10760c 100644 --- a/docs/bindings-conception.md +++ b/docs/bindings-conception.md @@ -220,3 +220,43 @@ Premier cas concret, à faire en régression (les mêmes variables doivent être - `host_vars` du consommateur vs `group_vars` du groupe (défaut : host_vars, plus précis) ; - format exact des gabarits (`{cible.fqdn}`) et jeu d'attributs figés ; - compat ascendante du `consommateur` des bases pendant la migration. + +## 11. Taxonomie des liaisons : niveau × modalité (ajout 2026-07-04) + +« Liaison » est le concept-chapeau : toute relation déclarative que le moteur câble. Elle se +classe sur **deux axes indépendants**. + +### Axe 1 — le niveau (le sous-type nommé) +- **`liens`** (dans `applications.yml`) : liaisons **app → app / base / domaine / annuaire**, + résolues en **config** (host_vars, lookups registre). +- **`intégrations`** (dans `serveurs.yml`) : liaisons **nœud → service de flotte** (PKI, sauvegarde, + métriques, journaux, MTA, DNS, annuaire), résolues en **appartenance de groupe + un agent client**. + +### Axe 2 — la modalité (requise vs optionnelle) — **orthogonale au niveau** +- **Requise (constitutive)** : sans elle, l'entité **ne peut pas se concrétiser**. Son absence est + une **erreur** → le moteur doit **refuser d'instancier** (fail-fast, message clair). +- **Optionnelle (élective)** : un **choix** de l'opérateur, activé au cas par cas. Son absence est + **légitime** → jamais d'erreur. + +La modalité est une propriété de **chaque** liaison, pas du sous-type. Grille : + +| | **Requise** | **Optionnelle** | +|---|---|---| +| **App** (`liens`) | keycloak → sa base PostgreSQL | forgejo → SSO (auth locale possible) | +| **Nœud** (`intégrations`) | client_pki sur un nœud qui sert LDAPS | client_journal → Loki | + +### État actuel — le requis est déjà appliqué, mais **implicitement** +- `resoudre_base` **assert** l'entrée BD ; le registre **exige** `serveur:` sur une base ; + `docs/dependances-groupes.yml` déclare les dépendances dures ; `bases_donnees.py verifier` valide. +- L'optionnel = les **listes opt-in** (`integrations:`, `expose:`). +- **Rien ne déclare** « ce lien est requis / celui-ci est électif » — c'est déduit d'*où* il est écrit. + +### Raffinement proposé (incrémental, compatible plan-de-contrôle-gelé) +Rendre la modalité **explicite** : chaque liaison porte (ou dérive) un `requis: true|false`. +- **requise absente** → refus d'instancier, message actionnable (renforce « exploitable sans IA ») ; +- **optionnelle absente** → choix assumé, silence. + +La validation du requis existe déjà à moitié ; il s'agit de l'**uniformiser et de la nommer**, pas +de refondre. Exemple de nature : les agents `client_metrique` / `client_journal` / `client_smtp` +sont des liaisons **nœud × optionnelle** — d'où leur forme d'**intégration opt-in**, activée +sciemment par nœud (superviser *ce* nœud est un choix, pas une dépendance intrinsèque).