docs(bindings) : taxonomie des liaisons (niveau × modalité)

§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 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-07-04 11:39:40 -04:00
parent ecc7b2767b
commit 346a6a5192

View file

@ -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).