Set-OPS-Public/docs/audit/affirmations.md
Daniel Allaire 835f8ab6d0 Mise en conformité prouvable : registre d'affirmations + make prouver
Le dépôt fait / explique / prouve ce qu'il affirme, vérifiable en une commande.

- Phase 1 : docs/audit/affirmations.md — 54 affirmations publiques tracées vers
  une commande de preuve et un statut (/🟡//).
- Phase 2 : CLAUDE.md réduit à un pointeur mince ; contradiction SSH levée (le
  code applique déjà PasswordAuthentication no + AuthenticationMethods publickey,
  conforme à AGENTS.md) ; section AGENTS « Codex » → « agents IA ».
- Phase 3 : parcours démarrage réparé (QUICKSTART renvoyait à un modèle absent,
  chemins de voûte faux, commandes make périmées) ; make verifier vert
  (ansible-lint 33 → 0 : site.yml généré nommé, pipefail, name[template]) ;
  voûte Proxmox unifiée lue par le clonage (all/vault.yml).
- Phase 4 : make prouver → docs/audit/preuve-<date>.md, harnais rejouable qui
  rappelle l'outillage existant (aucune validation réimplémentée).
- Phase 5 : parcours QUICKSTART prouvé hors-ligne sur le socle ; modèle socle
  rendu valide (autorite interne → auto-heberge) ; split-brain d'inventaire
  corrigé (repli sur le répertoire existant, pas principal/).

make prouver : 15 OK, 0 échec, 1 sautée (voûte). ansible-lint : 0 failure.
Écarts découverts en cours de traitement (AFF-097..100) : tous résolus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 19:53:18 -04:00

390 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Registre des affirmations — Set-OPS
> **Phase 1 de la mise en conformité prouvable.** Ce document est un **audit**, sans
> aucun correctif de code ni de documentation. Chaque affirmation publique vérifiable
> du dépôt est tracée vers une commande de preuve reproductible, ou marquée comme
> invérifiable.
>
> Règle d'arbitrage (rappel) : *le dépôt ne doit jamais affirmer plus que ce qu'il
> prouve.* Les traitements (corriger la doc / corriger le code / chantier séparé)
> relèvent de la **Phase 3** — ils ne sont **pas** appliqués ici.
- **Date de l'audit** : 2026-07-20
- **Instance montée pendant l'audit** : `instance -> ../OPS-Technolibre` (inventaire `principal/`)
- **Outillage** : ansible-core 2.18.1, ansible-lint 25.1.3, Python 3.13.3, node présent.
- **Périmètre** : surfaces publiques uniquement — `README.md`, `AGENTS.md`,
`CLAUDE.md`, `QUICKSTART.md`, `SOLUTION.md`, `docs/`, `wiki/`, aide du `Makefile`,
libellés du GUI. Aucune VM / Proxmox / réseau touché (mission hors production).
Légende du statut : ✅ prouvée · 🟡 partielle · ❌ fausse · ⚪ invérifiable localement.
---
## 1. README.md
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-001 | « Set-OPS est un moteur Ansible générique … à partir d'un plan déclaratif » (README:3) | fonctionnelle | `python3 scripts/instancier.py generer && python3 scripts/instancier.py comparer` | ✅ | « DIFF VIDE : le plan reproduit exactement l'inventaire ». Générateur opérationnel. |
| AFF-002 | « Set-OPS s'exploite entièrement à la main — la doc, `make` et le GUI suffisent, sans aucune IA » (README:9 ; AGENTS principe 10) | doctrinale | Suivre `QUICKSTART.md` de bout en bout ; `make verifier` | 🟡 | Le principe tient au niveau outillage, mais **deux trous cassent le parcours sans IA** : `make verifier` échoue (AFF-006) et `QUICKSTART` étape 2 renvoie à un modèle absent (AFF-020/021). Un opérateur seul bute. |
| AFF-003 | Registres = source unique de vérité : `serveurs.yml`, `applications.yml`, `bases-donnees.yml`, `domaines.yml`, `nomenclature.yml` (README:15) | structurelle | `make inventaire-verifier` (serveurs/applications/bases/domaines) | ✅ | Les 4 validateurs renvoient « Registre valide ». Fichiers présents dans `instance/plan/`. |
| AFF-004 | « `instance/inventories/production/hosts.yml` est généré depuis le plan — ne pas l'éditer à la main » (README:34) | procédurale | `python3 scripts/instancier.py comparer` (diff-vide) | ✅ | Diff vide confirmé. (Nuance de chemin : l'instance courante utilise `principal/` — voir AFF-023.) |
| AFF-005 | « Afficher l'aide : `make` » (README:86) | procédurale | `make` (défaut = cible `aide`) | ✅ | `.DEFAULT_GOAL := aide` ; l'aide s'affiche. |
| AFF-006 | « Valider le dépôt : `make verifier` » (README:91) | fonctionnelle | `make verifier` | ❌ | `make lint` (1re dépendance de `verifier`) **échoue rc=2** : ansible-lint rapporte « Failed: 33 failure(s) » (`name[play]` sur le `site.yml` généré, `risky-shell-pipe` dans `site.yml`/`valider.yml`, `name[template]`). `make verifier` ne passe donc **pas** sur un dépôt propre. |
| AFF-007 | « Inspecter … `make hote-afficher HOTE=web-frontal-01` » (README:98) | procédurale | `make hote-afficher HOTE=web-frontal-01` | 🟡 | La cible existe et fonctionne, mais l'hôte d'exemple `web-frontal-01` n'existe pas dans l'instance courante → l'exemple littéral échoue (exemple générique, pas garanti par instance). |
| AFF-008 | « Chaque groupe opérationnel doit avoir son playbook homonyme dans `playbooks/groupes/` » (README:120 ; AGENTS:316) | structurelle | `python3 scripts/inventory_host.py --inventaire instance/inventories/principal/hosts.yml verifier-playbooks --dossier-playbooks playbooks/groupes` | ✅ | rc=0. Les 30 groupes opérationnels ont leur playbook. Seuls `hotes_actifs`, `hotes_planifies`, `modeles_vm` (groupes méta/état) n'en ont pas — exclus par conception. |
| AFF-009 | « Les dépendances causales entre groupes sont dans `docs/dependances-groupes.yml` » (README:128 ; AGENTS:413) | structurelle | `python3 scripts/inventory_host.py … verifier-dependances …` | ✅ | rc=0. Aucune entrée ne référence un rôle/groupe inexistant. |
| AFF-010 | « Le runbook du DNS interne initial est dans `docs/dns-interne.md` » (README:130) | structurelle | `test -f docs/dns-interne.md` | ✅ | Fichier présent. |
| AFF-011 | « La nomenclature … est dans `docs/nomenclature-vm.md` » (README:132) | structurelle | `test -f docs/nomenclature-vm.md` | ✅ | Fichier présent. |
| AFF-012 | « Le catalogue des services … `docs/catalogue-services.md` » (README:126) | structurelle | `test -f docs/catalogue-services.md` | ✅ | Fichier présent. |
| AFF-013 | « `make creer-vm HOTE=… ` VMID/IP/VLAN/passerelle lus dans le plan » (README:138) | fonctionnelle | `python3 scripts/inventory_host.py … parametres-proxmox --hote <h>` | 🟡 | La dérivation existe (sous-commande `parametres-proxmox`), mais l'exécution réelle touche Proxmox → non testable localement (hors production). Mécanique de dérivation seule vérifiable. |
| AFF-014 | « Les déploiements de groupes ciblent automatiquement les hôtes actifs seulement » (README:171) | fonctionnelle | lecture `Makefile:261` : `--limit '$(GROUPE):&$(GROUPE_HOTES_ACTIFS)'` | ✅ | Intersection `groupe ∩ hotes_actifs` codée dans la cible `appliquer`. |
| AFF-015 | « Set-OPS est un logiciel libre … AGPLv3 … texte intégral dans `LICENSE` » (README:177-186) | structurelle | `test -f LICENSE` | ✅ | `LICENSE` présent. |
---
## 2. QUICKSTART.md
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-020 | « Les modèles sont dans `exemples/modeles/` … Choisis : `socle`, `presence-web`, `forge`, `identite`, `observabilite`, `integral` » (QUICKSTART:25-26) | structurelle | `ls exemples/modeles/` | ❌ | Le dossier public ne contient que `socle` (+ `README.md`). Les 5 autres modèles sont dans un dépôt **privé** `Set-OPS-modeles` (correctement expliqué dans `exemples/modeles/README.md`, mais **pas** dans QUICKSTART). |
| AFF-021 | « `cp -r exemples/modeles/presence-web ../mon-instance` » (QUICKSTART:29) | procédurale | exécuter la commande | ❌ | La commande **échoue** : `exemples/modeles/presence-web` n'existe pas. C'est la commande centrale de l'étape 2 ; un opérateur suivant QUICKSTART à la lettre est bloqué immédiatement. Seule valeur valide : `socle`. |
| AFF-022 | « `instance/inventories/production/group_vars/all.yml``domaine_interne` » (QUICKSTART:36) | structurelle | `test -f exemples/modeles/socle/inventories/production/group_vars/all.yml` | ✅ | Le modèle `socle` fournit bien ce fichier sous `production/`. |
| AFF-023 | « Tous tes secrets … `instance/inventories/lab/group_vars/all/vault.yml` » (QUICKSTART:48-49) | procédurale | `ls exemples/modeles/socle/inventories/` | ❌ | Le modèle `socle` n'a **pas** d'inventaire `lab/` (uniquement `production/`). Le chemin de voûte annoncé n'existe pas dans le modèle public ; incohérent avec AFF-022 (`production/`). |
| AFF-024 | « `make instancier` (diff) puis `make instancier-appliquer FORCE=1` — 1re génération » (QUICKSTART:68-70) | fonctionnelle | `make instancier` ; cible `instancier-appliquer` (Makefile:582) | ✅ | Cibles présentes ; `FORCE` mappé sur `--force`. Diff-vide prouve le mécanisme (AFF-001). |
| AFF-025 | Étape 5 : `make preparer-modele` / `verifier-modele` / `nettoyer-modele CONFIRMER=true` (QUICKSTART:59-62) | procédurale | cibles Makefile:632-643 | 🟡 | Cibles présentes et gardes vérifiées ; l'exécution réelle exige une VM Debian 13 + Proxmox → hors production, non testable ici. |
| AFF-026 | « Valider à tout moment : `make inventaire-verifier` / `make verifier` » (QUICKSTART:98-101) | fonctionnelle | `make inventaire-verifier` ; `make verifier` | 🟡 | `make verifier` échoue (AFF-006). `make inventaire-verifier` appelle `ansible-inventory --list` qui **exige le mot de passe Vault** (`ERROR! Attempting to decrypt but no vault secrets found` sans `ANSIBLE_VAULT_PASSWORD_FILE`) — prérequis non rappelé à cet endroit. |
---
## 3. AGENTS.md
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-030 | « RÈGLE D'OR : `…/production/hosts.yml` est un artefact GÉNÉRÉ » (AGENTS:43) | procédurale | `python3 scripts/instancier.py comparer` | ✅ | Diff vide : l'inventaire est reproductible depuis le plan. |
| AFF-031 | « `make instancier-appliquer` refuse si le diff n'est pas vide (`FORCE=1` sinon) » (AGENTS:47) | fonctionnelle | lecture `scripts/instancier.py appliquer` + Makefile:582-583 | ✅ | `appliquer` accepte `--force` (mappé `FORCE`) ; garde diff cohérente avec le comparateur. |
| AFF-032 | « VMID / IP / VLAN / passerelle sont dérivés de la `fonction` via la nomenclature » (AGENTS:49) | fonctionnelle | `python3 scripts/serveurs.py verifier` (réconcilie dérivation ↔ inventaire) | ✅ | « Registre des serveurs valide et réconcilié avec l'inventaire. » Dérivation confirmée. |
| AFF-033 | « garde-fous : … `node --check` du JS du GUI (`scripts/verifier_gui.py`, dans `make inventaire-verifier`) » (AGENTS:50) | fonctionnelle | `python3 scripts/verifier_gui.py` | ✅ | « JS du GUI : syntaxe valide (node --check). » |
| AFF-034 | « Chaque rôle qui utilise `notify` doit contenir son handler dans le rôle » (AGENTS:182) | structurelle | script de recoupement notify↔handlers sur tous les rôles | ✅ | « OK : tout `notify` pointe vers un handler existant dans le même rôle. » |
| AFF-035 | « Tout `notify` doit pointer vers un handler existant » (AGENTS:193) | structurelle | idem AFF-034 | ✅ | Aucun `notify` orphelin. |
| AFF-036 | « Playbooks … testables avec `--check` autant que possible » (AGENTS:214, 427) | fonctionnelle | `ansible-playbook … --check` sur cibles vivantes | ⚪ | Non testable hors flotte réelle (mission hors production). Recensement des rôles non-check reporté (nécessite des hôtes). |
| AFF-037 | État SSH attendu : `PasswordAuthentication no`, `AuthenticationMethods publickey` (AGENTS:538-542) | fonctionnelle | lecture `roles/ssh_baseline/defaults` + `templates/10-setops.conf.j2` | ✅ | Défauts = `no`/`no`/`yes` ; le template code `AuthenticationMethods publickey`. **Le code suit AGENTS.md.** (Contredit CLAUDE.md — voir AFF-050.) |
| AFF-038 | « Ne pas maintenir en parallèle `playbooks/socle/` ou `playbooks/durcissement/` » (AGENTS:278) | structurelle | `ls playbooks/` | ✅ | Ces dossiers n'existent pas ; socle/durcissement = groupes `serveur_debian`/`serveur_durci`. |
| AFF-039 | « Les playbooks peuvent être classés par domaine : groupes/ maintenance/ monitoring/ networking/ proxmox/ modeles_vm/ web/ database/ identity/ backup/ applications/ » (AGENTS:257-270) | structurelle | `find playbooks -maxdepth 1 -type d` | 🟡 | Seuls `groupes/`, `maintenance/`, `modeles_vm/`, `proxmox/` existent. Formulé au conditionnel (« peuvent ») → aspirationnel, pas une fausse affirmation, mais liste plus large que la réalité. |
| AFF-040 | Section « Comportement attendu de **Codex** » (AGENTS:650) | doctrinale | lecture | 🟡 | La section ne nomme que Codex alors qu'elle vaut pour tout agent (Claude inclus). Correctif de titrage prévu en Phase 2 (item 3). |
---
## 4. CLAUDE.md
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-050 | « Pendant la construction du template : `PasswordAuthentication yes` » (CLAUDE.md § SSH) | fonctionnelle | `roles/ssh_baseline/defaults/main.yml` | ❌ | Le code déploie `PasswordAuthentication no` **dès la construction** (`ssh_baseline_password_authentication: "no"`, template `AuthenticationMethods publickey`). CLAUDE.md contredit **et** le code **et** AGENTS.md (qui fait autorité). Cause racine : duplication de doctrine. Cible Phase 2 (item 1). |
| AFF-051 | « Claude Code doit lire et respecter `AGENTS.md` avant toute modification ; en cas de contradiction, suivre `AGENTS.md` » (CLAUDE.md § Instruction principale) | doctrinale | — | ✅ | Cohérent avec AGENTS.md ; pas de commande de preuve (déclaration de gouvernance). |
| AFF-052 | CLAUDE.md redéclare la doctrine de template, SSH, pare-feu, cloud-init, handlers, actions destructives (dupliquée d'AGENTS.md) | structurelle | `diff` conceptuel CLAUDE.md ↔ AGENTS.md | 🟡 | Large duplication → source des dérives (AFF-050). Réduction à un pointeur mince prévue Phase 2 (item 2). |
---
## 5. SOLUTION.md
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-060 | « On garde une seule structure : `inventories/ playbooks/ roles/ docs/` » (SOLUTION:11-18) | structurelle | `ls` racine | 🟡 | Réel : aussi `scripts/`, `filter_plugins/`, `exemples/`, `wiki/`, `instance/`. Description obsolète (antérieure au plan/GUI). |
| AFF-061 | Commande template : `ansible-playbook … debian13_proxmox_preparer.yml --ask-pass --ask-become-pass` (SOLUTION:24-25) | procédurale | comparaison avec la doctrine SSH clé-only | 🟡 | `--ask-pass` (mot de passe SSH) contredit l'accès **par clé dès le départ** d'AGENTS.md (AFF-037). SOLUTION.md décrit un flux périmé (mot de passe SSH) ; le flux réel = clé via cloud-init. |
| AFF-062 | « Le pare-feu `nftables` est installé et préparé, mais pas activé par défaut dans le template » (SOLUTION:60 ; AGENTS:559 ; CLAUDE.md) | fonctionnelle | `grep enabled roles/nftables_baseline/defaults/main.yml` | ✅ | `nftables_baseline_enabled: false`. `preparer-modele` inclut le rôle et affiche « nftables est installé mais désactivé par défaut ». |
---
## 6. Aide du Makefile (`make`)
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-070 | « `make site-verifier` valide la cohérence couches/graphe » (Makefile aide:133) | fonctionnelle | `python3 scripts/orchestrer.py verifier` | ✅ | « Orchestration cohérente : 30 groupes classés, aucun cycle, aucune arête en arrière. » |
| AFF-071 | « `make flux``docs/registre-flux.md` + `instance/flux-genere/*.nft` » (Makefile aide:146) | fonctionnelle | `python3 scripts/resoudre_flux.py verifier` ; en-tête de `docs/registre-flux.md` | ✅ | « Flux cohérents : 29 rôles, 63 flux ». Le registre porte l'en-tête « GÉNÉRÉ par `scripts/resoudre_flux.py` ». |
| AFF-072 | « `make deployer-tout` — déploiement orchestré de la flotte ; garde `CONFIRMER` » (Makefile aide:138) | fonctionnelle | lecture Makefile:352-357 | 🟡 | Garde `CONFIRMER=true` vérifiée (refuse sinon, rc=2). Déploiement réel hors production → non exécuté. |
| AFF-073 | « `make wiki-publier` … refuse sans `WIKI_REMOTE` » (Makefile aide:151) | fonctionnelle | lecture Makefile:320-326 | ✅ | Garde présente : refus + message d'usage si `WIKI_REMOTE` vide. |
| AFF-074 | « `make devis-reseau` — dérivé des nomenclatures » (Makefile:309) | fonctionnelle | `python3 scripts/devis_reseau.py` | 🟡 | Dérive des instances fédérées `../*/plan/nomenclature.yml` (schéma `ip-miroir`) ; sortie dépend du voisinage de dépôts → vérifiable seulement dans un contexte fédéré. |
| AFF-075 | Cibles dépréciées `make hote-planifier / hote-ajouter / hote-groupes` renvoient vers le plan (README:118 ; Makefile:237) | procédurale | `make hote-planifier` | ✅ | Stub présent : message « Cible dépréciée … » + `exit 2`. |
---
## 7. docs/ — runbooks et cohérence des commandes
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-080 | « `make help` — liste des cibles » (docs/config-proxmox.md:114) | procédurale | `grep -E '^help:' Makefile` | ❌ | Aucune cible `help`. La cible réelle est `aide` (défaut). Commande citée inexistante. |
| AFF-081 | « `make syntax-template` » (docs/modeles_vm/debian13-proxmox.md:77) | procédurale | `grep syntax-template Makefile` | ❌ | Aucune cible `syntax-template`. Réel : `syntaxe-modele`. Nom périmé. |
| AFF-082 | « `make syntax-template` » (docs/MISE-A-JOUR-CODEX-CLAUDE.md:146) | procédurale | idem | ❌ | Même nom périmé, second emplacement. |
| AFF-083 | Tous les docs cités par README/QUICKSTART/AGENTS existent (`plan-et-generation`, `positionnement`, `bindings-conception`, `flux-conception`, `couches-deploiement.yml`, `registre-flux.md`, `carte-set-ops`, `runbooks-exploitation`, `vm-lifecycle`, `procedure-template-…`, `dns-interne`, `nomenclature-vm`, `config-proxmox`, `catalogue-services`, `dimensionnement-ressources`, `exemples/vault.exemple.yml`, `exemples/instance.exemple.yml`) | structurelle | `test -f` sur chaque chemin | ✅ | 17/17 présents. |
| AFF-084 | « `docs/dependances-groupes.yml` — chaque groupe existant y figure, aucune entrée ne référence un rôle supprimé » (AGENTS:345,413) | structurelle | `verifier-dependances` (AFF-009) | ✅ | Validé ; graphe sans cycle, tri topologique réussi (via `orchestrer verifier`). |
| AFF-097 | Chemins d'inventaire `lab/` codés en dur pour la config/voûte **Proxmox** et le template, alors que `make config`/`cloner-vm` résolvent `lab > principal > production` (modèle `socle` = `production/`) | procédurale | `grep -rn 'inventories/lab/group_vars' docs playbooks` ; `scripts/config_proxmox.py:31` | 🟡 | **Découvert en Phase 3 (lot A).** Reste `lab/` codé en dur dans `docs/vm-lifecycle.md:171`, `docs/procedure-template-debian13-proxmox.md:741,747`, `docs/modeles_vm/debian13-proxmox.md:89`, `playbooks/proxmox/README.md:31,43,49,50`, `playbooks/proxmox/cloner_vm_debian.yml:45` (message). Non bloquant (l'outillage résout), mais trompeur pour le socle. **Différé** au lot « voûte Proxmox » (couplé à AFF-098). |
| AFF-099 | Le modèle public `socle` livre un `plan/domaines.yml` **invalide** : `exemple.internal` en `autorite: interne`, rejeté par le validateur (`auto-heberge`/`delegue`/`primaire-cache` attendus) | fonctionnelle | `SETOPS_INSTANCE=exemples/modeles/socle python3 scripts/domaines.py verifier` | ❌ | **Découvert Phase 5.** Un opérateur suivant QUICKSTART bute à la validation (étape 9 / `make inventaire-verifier`). `interne` = valeur périmée (déjà corrigée ailleurs en `auto-heberge`, cf. CHANGELOG 2026-07-07). |
| AFF-100 | `instancier.py`/`inventory_gui.py` résolvent `principal > production` mais **retombent sur `principal`** quand aucun `hosts.yml` n'existe encore ; le socle est en `production/` → 1ʳᵉ génération dans `principal/`, à côté des `group_vars` restés en `production/` (split-brain) | fonctionnelle | parcours QUICKSTART hors-ligne sur une copie du socle (`generer`→`appliquer`) | ❌ | **Découvert Phase 5.** `config_proxmox.py` détecte le répertoire existant (→ `production/`) ; `instancier`/GUI non → incohérence. QUICKSTART étapes 6-9 cassées pour le socle. |
| AFF-098 | Contradiction fonctionnelle voûte Proxmox : `make config` écrit le token dans la voûte unifiée `all/vault.yml` (et `config-proxmox.md` dit de **supprimer** `proxmox.vault.yml`), mais le clonage `cloner_vm_debian.yml` (lancé `-i localhost,`) ne charge le secret **que** depuis `proxmox.vault.yml`/`proxmox.local.yml` ou les variables d'env — **jamais** `all/vault.yml` | fonctionnelle | lecture `playbooks/proxmox/cloner_vm_debian.yml:11-12,51-64` vs `scripts/config_proxmox.py:35` | ❌ | **Découvert en Phase 3 (lot B).** Un opérateur qui suit la voûte unifiée met le token dans `all/vault.yml``make creer-vm` échoue l'assert (`proxmox_api_token_secret` vide), sauf variables d'env ou `proxmox.vault.yml` conservé. **Traitement B (code)** : faire lire `all/vault.yml` par le clonage, ou faire écrire `proxmox.vault.yml` par `make config`. À arbitrer dans le lot « voûte Proxmox ». |
---
## 8. wiki/
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-090 | Le wiki pédagogique fournit des unités d'apprentissage par service (`wiki/*.md`) publiables dans Forgejo | structurelle | `ls wiki/*.md` | ✅ | 16 pages de contenu (+ `README.md` + `_Sidebar.md`) ; 17 publiées par `wiki-publier` (README exclu). |
| AFF-091 | Contenu conceptuel du wiki (OIDC, PKI, DNS, sauvegardes, idempotence, RBAC…) | doctrinale | — | ⚪ | Contenu pédagogique = affirmations conceptuelles, non rattachées à une preuve exécutable du dépôt. Hors périmètre de preuve automatisable. |
---
## 9. GUI (libellés)
| ID | Affirmation (source) | Type | Commande de preuve | Statut | Écart constaté |
|---|---|---|---|---|---|
| AFF-095 | « La vue **Inventaire** est en lecture seule ; vues éditables **Serveurs**, **Applications**, **Domaines** ; vues lecture seule **Réseau**, **Flux**, **Couches** » (README:41 ; AGENTS:48 ; CHANGELOG) | fonctionnelle | démarrage headless de `scripts/inventory_gui.py` + inspection des routes/onglets | 🟡 | Les routes backend et l'import des validateurs sont présents dans `scripts/inventory_gui.py` ; le rendu des onglets et le caractère « lecture seule » ne sont pas vérifiés sans lancer le serveur + un navigateur (non fait — pas de commande de preuve headless au registre). |
| AFF-096 | « GUI 100 % française » (CHANGELOG 2026-07-03) | structurelle | inspection des chaînes du GUI | ⚪ | Vérifiable seulement par revue exhaustive des libellés rendus ; non automatisé ici. |
---
## Décompte
Recompte exact par ID (numérotation à trous AFF-001 → AFF-096, **54 affirmations**).
| Statut | Nombre |
|---|---|
| ✅ prouvée | 30 |
| 🟡 partielle | 13 |
| ❌ fausse | 8 |
| ⚪ invérifiable localement | 3 |
| **Total** | **54** |
Détail :
- ✅ (30) : AFF-001, 003, 004, 005, 008, 009, 010, 011, 012, 014, 015, 022, 024, 030, 031, 032, 033, 034, 035, 037, 038, 051, 062, 070, 071, 073, 075, 083, 084, 090.
- 🟡 (13) : AFF-002, 007, 013, 025, 026, 039, 040, 052, 060, 061, 072, 074, 095.
- ❌ (8) : AFF-006, 020, 021, 023, 050, 080, 081, 082.
- ⚪ (3) : AFF-036, 091, 096.
> La Phase 4 (`make prouver`) rattachera chaque ✅ à sa section de preuve et figera le
> compte.
---
## Les dix écarts les plus graves
Classés par risque pour un opérateur qui suit la doc **à la lettre, sans IA**.
1. **AFF-021 / AFF-020 — QUICKSTART renvoie à un modèle inexistant.**
`cp -r exemples/modeles/presence-web ../mon-instance` échoue : seul `socle` est
public. **L'opérateur est bloqué dès l'étape 2** du guide de démarrage. Risque
maximal : c'est la toute première action concrète du parcours « zéro → écosystème ».
2. **AFF-006 — `make verifier` échoue sur un dépôt propre.**
`ansible-lint` rapporte 33 échecs (surtout `name[play]` sur le `site.yml` **généré**
par l'outil lui-même, + `risky-shell-pipe`). La commande de validation vantée par
README et QUICKSTART ne passe pas → l'opérateur croit son dépôt cassé, ou apprend à
ignorer l'échec (perte de confiance dans le harnais).
3. **AFF-050 — Contradiction SSH doc vs code (sécurité).**
`CLAUDE.md` prescrit `PasswordAuthentication yes` pendant la construction ; le code
et `AGENTS.md` imposent `no` + `AuthenticationMethods publickey`. Un opérateur qui
suit CLAUDE.md attend un accès mot de passe qui n'existe pas — et la doctrine de
sécurité affichée est contradictoire.
4. **AFF-023 — Chemin de voûte faux dans QUICKSTART.**
L'étape 4 place les secrets dans `inventories/lab/group_vars/all/vault.yml`, mais le
modèle public `socle` n'a pas d'inventaire `lab/` (seulement `production/`).
L'opérateur crée sa voûte au mauvais endroit → déchiffrement introuvable au déploiement.
5. **AFF-026 — `make inventaire-verifier` exige le Vault sans le dire.**
La validation « à tout moment » appelle `ansible-inventory --list` qui échoue
(`no vault secrets found`) sans `ANSIBLE_VAULT_PASSWORD_FILE`. Prérequis non rappelé
au point d'usage → échec surprenant pour qui n'a pas exporté sa clé.
6. **AFF-002 — Promesse « exploitable sans IA » entamée par 15.**
Le principe fondateur (AGENTS principe 10) est **partiellement démenti par les faits** :
le parcours documenté comporte au moins deux ruptures dures (modèle absent, `make
verifier` cassé). C'est le méta-risque : la doc ne mène pas seule au succès.
7. **AFF-080 / AFF-081 / AFF-082 — Commandes `make` périmées dans la doc.**
`make help` (→ `aide`) et `make syntax-template` (→ `syntaxe-modele`, cité 2×)
n'existent pas. L'opérateur tape une commande qui renvoie une erreur `make`.
8. **AFF-061 — SOLUTION.md décrit un flux SSH périmé.**
`--ask-pass --ask-become-pass` suppose un accès par mot de passe contraire au modèle
clé-only réel. Suivre SOLUTION.md pour construire le template mène à un flux qui ne
correspond plus au code.
9. **AFF-060 — SOLUTION.md décrit une arborescence obsolète.**
« Une seule structure : inventories/playbooks/roles/docs/ » ignore `scripts/`,
`instance/`, `filter_plugins/`, `wiki/`, `exemples/` — désoriente un nouveau lecteur
sur l'endroit où vivent le plan et le GUI.
10. **AFF-052 / AFF-040 — Doctrine dupliquée et titrage « Codex ».**
La duplication CLAUDE.md ↔ AGENTS.md est la **cause racine** de la contradiction n°3 ;
la section « Comportement attendu de Codex » sous-entend à tort qu'elle ne vise pas
Claude. Risque de gouvernance : deux sources d'autorité qui divergent avec le temps.
---
## Journal des traitements
Le tableau ci-dessus est le **snapshot d'audit Phase 1 (2026-07-20)** et n'est pas
réécrit. Les traitements appliqués ensuite sont consignés ici, datés et traçables.
### Phase 2 — 2026-07-20 (3 incohérences internes pré-cadrées)
- **AFF-050 (❌ → résolu)** — Doctrine SSH contradictoire. Vérifié que le code applique
déjà `PasswordAuthentication no` + `AuthenticationMethods publickey` dès la construction
(aligné sur `AGENTS.md`, cf. AFF-037). **Aucun correctif de code** ; la doctrine SSH a
été **retirée de `CLAUDE.md`**.
- **AFF-052 (🟡 → résolu)** — Duplication CLAUDE.md ↔ AGENTS.md. `CLAUDE.md` réduit à un
pointeur mince (autorité d'`AGENTS.md` + 5 règles absolues) ; cause racine d'AFF-050 supprimée.
- **AFF-040 (🟡 → résolu)** — Section « Comportement attendu de **Codex** » renommée
« …des agents IA » dans `AGENTS.md`, avec mention explicite qu'elle vaut pour tout agent.
Reste ouvert après Phase 2 : les 5 ❌ restants (AFF-006, 020, 021, 023, 080/081/082) et
les 🟡 relèvent de la **Phase 3 (arbitrage)**.
### Phase 3 — Lot A « doc de démarrage » — 2026-07-20
- **AFF-020/021 (❌ → résolu, A)** — `QUICKSTART.md` étape 2 : ne propose plus que le
modèle public `socle` (`cp -r exemples/modeles/socle …`) ; les modèles assemblés
renvoyés au dépôt privé `Set-OPS-modeles`, cohérent avec `exemples/modeles/README.md`.
- **AFF-023 (❌ → résolu, A + correctif d'exemple)** — Chemin de voûte corrigé
`lab/``production/` dans `QUICKSTART.md`, `exemples/vault.exemple.yml` et
`docs/config-proxmox.md`. **Piège corrigé** : le modèle `socle` livrait ses intrants en
`production/group_vars/all.yml` (forme fichier) ; ajouter `all/vault.yml` (forme dossier)
**masque silencieusement** le fichier `all.yml` (vérifié empiriquement : seul le dossier
est chargé). Le modèle a été converti en forme dossier (`all/10-intrants.yml`), alignée
sur l'instance prouvée `principal`. Validé : `ansible-inventory --host` charge bien
`domaine_interne` depuis la nouvelle disposition.
- **AFF-080/081/082 (❌ → résolu, A)** — Commandes `make` périmées corrigées :
`make help``make` (`docs/config-proxmox.md`) ; `make syntax-template`
`make syntaxe-modele` (`docs/modeles_vm/debian13-proxmox.md`,
`docs/MISE-A-JOUR-CODEX-CLAUDE.md`).
- **AFF-097 (🟡, découvert)** — `lab/` codé en dur restant dans les docs template/clone
(étapes 5+). Consigné ci-dessus ; **non traité dans ce lot** (lot séparé à prévoir).
### Phase 3 — Lot B « doc (prose) » — 2026-07-20
- **AFF-026 (🟡 → résolu, A)** — `QUICKSTART.md` § « Valider à tout moment » : note ajoutée
que `inventaire-verifier`/`verifier` chargent l'inventaire complet et exigent
`ANSIBLE_VAULT_PASSWORD_FILE` (étape 4), sinon « no vault secrets found ».
- **AFF-039 (🟡 → résolu, A)** — `AGENTS.md` : note ajoutée sous la liste des sous-dossiers
`playbooks/` — seuls `groupes/`, `maintenance/`, `modeles_vm/`, `proxmox/` sont peuplés ;
les autres sont **prospectifs**.
- **AFF-060/061 (🟡 → résolu, A)** — `SOLUTION.md` : bannière « document historique » ajoutée
(supplanté par README/QUICKSTART/`make`) ; arborescence complétée (`scripts/`, `wiki/`,
`instance/`…) ; commande de construction `--ask-pass` (mot de passe) remplacée par
`make preparer-modele` (accès par clé, aligné `AGENTS.md`).
- **AFF-002 (🟡)** — « exploitable sans IA » : **pas de reformulation** (c'est un engagement
fondateur légitime, pas une sur-affirmation). Son seul écart résiduel est AFF-006
(`make verifier` casse) → bascule ✅ une fois AFF-006 traité (lot C, B). Aucune édition.
- **AFF-007 (🟡)** — `web-frontal-01` : **assumé** comme nom d'exemple/placeholder (usage
cohérent dans tout le README) ; aucune édition.
- **AFF-097 / AFF-098** — **différés** au lot « voûte Proxmox » : AFF-098 (contradiction
fonctionnelle `all/vault.yml` ↔ clonage, traitement B) est couplé à AFF-097 (mêmes
fichiers) ; les traiter ensemble évite un double passage.
### Phase 3 — Lot « voûte Proxmox » — 2026-07-20
- **AFF-098 (❌ → résolu, B, option a)** — Le clonage lit désormais la voûte **unifiée**.
`playbooks/proxmox/cloner_vm_debian.yml` : `all/vault.yml` ajouté à la liste des sources
de secrets Proxmox (chargé via le filtre `is search('vault')`, autoritaire car en
dernier). `Makefile` (`cloner-vm`) : la détection de voûte chiffrée cherche d'abord
`group_vars/all/vault.yml` puis `proxmox.vault.yml` (déclenche `--ask-vault-pass`).
Messages de tâche/rescousse/assert rendus génériques. **Validé** : `--syntax-check` OK,
`ansible-lint` 0 échec sur le playbook, et **test fonctionnel** (mini-instance en clair) —
le token est bien chargé depuis `all/vault.yml` et l'hôte depuis `proxmox.yml`
(assert vert). `proxmox.vault.yml` reste accepté en compatibilité.
- **AFF-097 (🟡 → résolu, A)** — `lab/` codé en dur retiré des docs Proxmox/template :
`playbooks/proxmox/README.md`, `docs/procedure-template-debian13-proxmox.md`,
`docs/vm-lifecycle.md`, `docs/modeles_vm/debian13-proxmox.md``production/` + voûte
unifiée. Plus aucune référence `inventories/lab/group_vars` dans les fichiers suivis
(hors `tmp/` gitignoré et la section *migration* de `config-proxmox.md`, intentionnelle).
### Phase 3 — Lot C « make verifier vert » — 2026-07-20
- **AFF-006 (❌ → résolu, B)** — `ansible-lint` passe de **33 échecs à 0** (profil monté
`min``production`), donc `make lint` **rc=0**. Trois causes traitées :
- **30× `name[play]`** sur le `site.yml` **généré**`scripts/orchestrer.py` (`rendre_site`)
émet désormais `- name: Couche <c> — groupe <g>` avant chaque `import_playbook` ;
`site.yml` régénéré (`make site`). Logique d'orchestration inchangée (`orchestrer verifier`
OK, 30 groupes, syntax-check OK).
- **2× `risky-shell-pipe`** (`playbooks/valider.yml`) → `set -o pipefail;` +
`executable: /bin/bash` sur les deux tâches shell à pipe.
- **1× `name[template]`** (`playbooks/proxmox/supprimer_vm_debian.yml`) → Jinja déplacé en
fin de `name` (`… (VMID {{ … }})`).
- **Validé** : `make lint` rc=0 ; `make verifier` franchit lint + test (4) + `site-verifier`
+ `flux-verifier` + `syntaxe` (35 playbooks) — **toutes vertes**. Seule `inventaire-verifier`
exige la voûte de l'opérateur (`ANSIBLE_VAULT_PASSWORD_FILE`), prérequis documenté (AFF-026).
- **AFF-002 (🟡 → ✅)** — « exploitable sans IA » : ses deux écarts résiduels sont soldés
(parcours QUICKSTART, lot A ; `make verifier`/lint, ce lot). Bascule ✅, sous le prérequis
Vault désormais rappelé (AFF-026).
### Phase 5 — Boucle documentaire — 2026-07-20
Relecture de cohérence bout-en-bout (README, QUICKSTART, docs, wiki) contre le code final,
au regard du critère du principe 10 : *un opérateur sans IA exécute chaque procédure sans
commande morte, chemin faux ni étape manquante.*
- **Sweep commandes/chemins** : toutes les commandes `make` citées existent ; jetons périmés
(`presence-web` hors contexte, `syntax-template`, `make help`, `--ask-pass`, voûte `lab/`)
soldés (les occurrences restantes ne sont que dans `CHANGELOG.md`/`docs/audit`, historiques).
- **AFF-099 (❌ → résolu, B)** — `exemples/modeles/socle/plan/domaines.yml` : `interne`
`auto-heberge`. Le modèle public valide désormais.
- **AFF-100 (❌ → résolu, B)** — `instancier.py` et `inventory_gui.py` : le repli sans
`hosts.yml` vise maintenant le **répertoire d'inventaire existant** (→ `production/` pour le
socle) avant de retomber sur `principal`. Instances existantes (avec `hosts.yml`) inchangées.
- **Cohérence GUI/doc** — `docs/intrants-communs.md` : `group_vars/all.yml`
`group_vars/all/10-intrants.yml` (le GUI écrit déjà en forme dossier). `QUICKSTART.md`
étape 8 : exemple `serveur_postgresql``serveur_powerdns` (groupe présent dans le socle).
- **Preuve bout-en-bout (hors-ligne)** : parcours QUICKSTART rejoué sur une copie du socle —
`instancier generer`→`comparer`→`appliquer --force` **écrit `production/hosts.yml`**, diff
**vide** ensuite (idempotence), et les 4 validateurs verts (`serveurs` **réconcilié**).
Non-régression vérifiée sur l'instance réelle `principal` (diff vide, cible inchangée).
## Couverture par `make prouver` (Phase 4)
Chaque affirmation ✅ est soit **rejouée** par une preuve de `make prouver`
(`scripts/prouver.py` → `docs/audit/preuve-<date>.md`), soit **structurelle/doctrinale**
(vérifiée à l'audit, rien d'exécutable à rejouer en boucle).
| Affirmation ✅ | Preuve `make prouver` |
|---|---|
| AFF-001, 004, 030, 031, 032 | **P03** (diff-vide) |
| AFF-003 | **P06** (validateurs de registres) |
| AFF-008 | **P04** (groupes ↔ playbooks) |
| AFF-009, 084 | **P05** (dépendances) |
| AFF-010, 011, 012 | **P12** (existence des runbooks) |
| AFF-015, 022, 037, 038, 062 | **P13** (invariants structurels) |
| AFF-033 | **P07** (GUI node --check) |
| AFF-034, 035 | **P10** (handlers ↔ notify) |
| AFF-070 | **P08** (orchestration) |
| AFF-071 | **P09** (flux) |
| AFF-083 | **P11** (syntaxe) + **P12** |
| AFF-097 | **P14** (pas de `lab/` codé en dur) |
| AFF-002, 006 | **P01** (lint) — + parcours démarrage corrigé |
| AFF-030 (inventaire complet) | **P15** (voûte requise ; sauté sinon) |
**Structurelles/doctrinales, hors harnais récurrent** (vérifiées à l'audit) : AFF-005
(`make`=aide), AFF-014 (ciblage `groupe:&hotes_actifs`), AFF-024 (`instancier-appliquer`,
couvert indirectement par P03), AFF-051 (autorité d'`AGENTS.md`), AFF-073/075 (gardes
`make wiki-publier`/`hote-planifier`), AFF-090 (comptage wiki).
**Déclarations d'intention (⚪ — assumées, jamais présentées comme prouvées)** : AFF-036
(`--check` réel), AFF-091 (contenu wiki), AFF-096 (GUI 100 % français), AFF-007
(placeholder `web-frontal-01`). Reprises dans la section dédiée de chaque `preuve-<date>.md`.
## Limites de cet audit
- **Hors production** : toute affirmation nécessitant une VM, Proxmox, le réseau ou la
flotte vivante (`make valider`, `make deployer*`, `make creer-vm`, `--check` réel, les
très nombreux « **prouvé sur VM réelles** » du `CHANGELOG.md`) est marquée ⚪ ou 🟡 —
**non rejouable localement par conception**. Le `CHANGELOG.md` n'étant pas une surface
publique listée, ses affirmations « prouvé » ne sont pas enregistrées ici ; à noter que
`AGENTS.md` (« pas encore exécuté contre des VM réelles », « ne jamais présenter un rôle
non déployé comme en production ») encadre correctement cette réserve.
- **GUI** : pas de preuve headless au registre (AFF-095/096 en 🟡/⚪).
- **Vault** : l'instance courante chiffre `group_vars/all/vault.yml` ; les commandes qui
chargent l'inventaire complet via Ansible exigent le mot de passe Vault, non fourni
pendant l'audit (les validateurs Python lisent `hosts.yml`/le plan directement et
n'en ont pas besoin — d'où leur usage ici).
- **Numérotation à trous** : les ID sautent (AFF-001…096) pour laisser de la place par
surface ; ce n'est pas une omission.