Set-OPS-Public/docs/audit/plan-de-recette.md
Daniel Allaire 79461fdc38
Some checks failed
verifier / verifier (push) Has been cancelled
filiation : signer, inscrire la parente, et compter les temoins
L'exploitant : « j'ai une intuition : blockchain ». L'intuition visait le bon probleme —
une memoire partagee, verifiable, sans centre — mais la reponse etait deja dans git.

GIT EST DEJA UNE CHAINE DE HACHAGE : chaque commit porte l'empreinte de son parent, un
arbre de Merkle. Ce qui manquait n'etait pas la chaine mais l'AUTEUR : `user.name` est
declaratif, et toute la soiree du 20 des commits ont porte « Daniel Allaire » sans qu'aucune
preuve ne les lie a une cle (verifie : 8 commits, 0 signature, 0 etiquette).

POSE AUJOURD'HUI :
- signature par cle SSH (celle que la forge connait deja), etiquettes signees par defaut ;
  premiere etiquette v2026.08.21, verifiee par `git verify-tag` ;
- `.git-allowed-signers` VERSIONNE : qui clone verifie sans rien demander a la forge, et
  sans lui faire confiance. Retirer une ligne revoque pour la suite ; le passe signe reste
  verifiable ;
- `scripts/genome.py` + trois cibles make : les QUATRE depots sans lesquels un ecosysteme
  ne renait pas (moteur, instance, hebergeur, modeles), DERIVES et non declares ;
- `parente.yml` par ecosysteme : de quel moteur il descend, a quel commit, sous quelle
  etiquette. Patient 0 descend de 742bcbf, etiquette v2026.08.21 ;
- P40 : la parente est inscrite, chaque depot se retrouve, chaque commit inscrit EXISTE
  encore (une histoire reecrite se voit la), chacun porte un remote. Sautee proprement
  quand l'instance n'est pas un depot git — le modele jetable de la CI.

POURQUOI PAS DE BLOCKCHAIN. Elle resout : qui ecrit ensuite, quand personne ne fait
confiance a personne et qu'il y a de l'argent en jeu. Aucun des trois ici. Et la
multiplicite qu'elle achete cher, la lignee la produit comme effet secondaire : chaque
enfant porte une copie du code dont il descend, donc reecrire l'histoire suppose de
convaincre TOUS les descendants. Le jour ou l'Alliance certifiera, ce sera un JOURNAL DE
TRANSPARENCE (Certificate Transparency, Sigstore), pas une chaine.

ENSEIGNE, pas seulement pose : nouvelle unite « Filiation, signatures et temoins » (moule
en quatre temps), onze termes au glossaire, et P39 les exige desormais.

make verifier 40 OK, 0 echec, 0 saute ; make ci idem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 12:56:29 -04:00

23 KiB
Raw Blame History

Plan de recette — tests d'acceptation manuels

GÉNÉRÉ depuis les exercices du wiki (wiki/*.md, section « ④ À toi de jouer ») par scripts/plan_recette.py — ne pas éditer à la main ; régénérer avec make plan-recette. La preuve P22 échoue si ce fichier n'est plus à jour.

Ce plan est le pendant manuel de make prouver : là où le harnais prouve le moteur par machine (P01–P21), ces gestes valident l'exploitation — ce qu'un humain fait, voit, casse et répare. Ensemble, ils couvrent les deux moitiés ; le côté humain est la preuve de l'affirmation « exploitable sans IA » (cf. protocole-operateur-independant.md).

89 gestes sur 22 unités · 19 en « casse-répare » · 5 doublés d'un garde-fou machine (colonne Preuve auto).

Honnêteté de couverture. La colonne Preuve auto n'est remplie que lorsqu'une preuve Pxx de make prouver couvre AUSSI le geste. Un « — » signifie manuel seul : aucune machine ne le garde, seul l'œil de l'opérateur le valide. Ce plan ne prétend pas à l'exhaustivité au-delà des exercices présents dans le wiki.

Autorisation & RBAC

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Sens le défaut Avant tout rôle, un nouvel utilisateur SSO est Viewer dans Grafana : il voit le dashboard Journaux de la flotte, mais pas l'icône Explore. 👁 observe —
2 Donne Editor testmail a le rôle grafana-editor → déconnecte/reconnecte-le (Grafana applique le rôle à la connexion) → Explore apparaît. 👁 observe —
3 Observe le claim Dans Keycloak (console admin) → Clients → grafana → Client scopes → Evaluate pour testmail : le jeton contient "roles": ["grafana-editor"]. C'est ② en vrai. 👁 observe —
4 Casse & répare Retire grafana-editor de testmail (ou renomme-le en grafana-viewer), reconnecte : Explore disparaît. Remets-le : il revient. Tu sens que c'est le rôle, pas l'identité, qui ouvre la porte. 🔨 casse-répare —

Source : Autorisation & RBAC · § À toi de jouer.

Bases de données

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Liste les bases (sur data-sql-01) : « commande » 👁 observe —
2 Vois l'isolation Chaque app a sa base et son compte — pas de compte partagé. 👁 observe —
3 Suis une liaison Ouvre plan/bases-donnees.yml : l'entrée keycloak (serveur, base, propriétaire, secret) est exactement ce que le rôle serveur_keycloak va lire pour se connecter. 👁 observe —
4 Casse & répare Change le mot de passe d'un compte dans PostgreSQL (garde l'ancien !) sans mettre à jour la voûte : l'app ne se connecte plus. Restaure : ça repart. Tu sens que la connexion = identité + secret cohérents des deux côtés. 🔨 casse-répare —

Source : Bases de données · § À toi de jouer.

Cache

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Écris/lis avec authentification (sur data-sql-01) : « commande » 👁 observe —
2 Teste le TTL : redis-cli -a … SET court 1 EX 5 puis GET court avant/après 5 s — il expire. 👁 observe —
3 Vois la borne : redis-cli -a … CONFIG GET maxmemory et … maxmemory-policy (LRU). 👁 observe —
4 Casse & répare Interroge sans mot de passe : redis-cli GET essai:1 → NOAUTH (refusé). Puis vide le cache (FLUSHALL) : rien ne casse dans l'écosystème — la vraie donnée est en base. Tu sens qu'un cache est jetable. 🔨 casse-répare —

Source : Cache · § À toi de jouer.

Courriel (SMTP / IMAP)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Envoie via la soumission :587 (client authentifié) : « commande » 235 Authentication successful puis 250 queued = ① en action. 👁 observe —
2 Lis la boîte (le MDA) : doveadm search -u testmail mailbox INBOX all | wc -l sur infra-mail-01. 👁 observe —
3 Casse & répare Coupe l'annuaire (arrête OpenLDAP), renvoie un courriel : Postfix rejette le destinataire (il ne peut plus valider en LDAP). Rallume OpenLDAP : ça repart. Tu sens la dépendance requise MTA → annuaire. 🔨 casse-répare —

Source : Courriel (SMTP / IMAP) · § À toi de jouer.

DNS & résolution de noms

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Le plancher, sans DNS Sur un nœud : « commande » 👁 observe —
2 Interroge l'autoritatif Demande à PowerDNS directement : « commande » 👁 observe —
3 Vois les couches Compare getent hosts (plancher) et dig (DNS) : deux chemins, même IP. 👁 observe —
4 Casse & répare Sur un nœud sans client_unbound, vide /etc/hosts de ses entrées chezlepro (garde une sauvegarde !) et coupe l'accès au DNS : la résolution interne échoue. Restaure /etc/hosts : ça remarche sans DNS. Tu viens de sentir pourquoi le planc… 🔨 casse-répare —

Source : DNS & résolution de noms · § À toi de jouer.

Filiation, signatures et témoins

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 — make genome — quatre dépôts ? Lequel n'a pas de remote ? Celui-là n'existe qu'ici. 👁 observe —
2 — git verify-tag v2026.08.21 — que se passe-t-il si tu retires ta ligne de .git-allowed-signers ? (remets-la ensuite) 👁 observe —
3 — make genome-inscrire, puis ouvre parente.yml. Dans un an, qu'est-ce que ce fichier te dira que ta mémoire ne dira plus ? 👁 observe —
4 — Demande-toi où sont les témoins aujourd'hui. Combien de copies vivantes du moteur existent, sur combien de machines distinctes ? C'est la vraie mesure de la résistance de la lignée — pas la longueur des clés. Voir aussi : Multi-instance… 👁 observe —

Source : Filiation, signatures et témoins · § À toi de jouer.

Identité & SSO

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Vis le SSO Ouvre https://grafana.lab.chezlepro.internal → « Se connecter avec Chezlepro » → testmail. Puis ouvre Forgejo, puis Icinga : tu n'es reconnecté nulle part. 👁 observe —
2 Observe le flux Rouvre Grafana en navigation privée, ouvre les outils dév (F12 → Réseau) : repère la redirection vers Keycloak, puis le retour avec un code=. C'est ① en action. 👁 observe —
3 Interroge l'annuaire (la source de vérité) Sur un nœud avec ldap-utils : « commande » Tu vois l'entrée que Keycloak fédère — il ne l'a pas recopiée. 👁 observe —
4 Casse & répare (la fédération) Dans la console admin Keycloak → User Federation → désactive le fournisseur LDAP. Reconnecte-toi : échec (l'IdP ne voit plus l'annuaire). Réactive : ça remarche. Tu viens de sentir la dépendance requise entre l'IdP et l'annuaire. 🔨 casse-répare —

Source : Identité & SSO · § À toi de jouer.

Infra as Code & idempotence

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Sens l'idempotence Redéploie un rôle déjà en place (ex. via la GUI ou make deployer HOTE=…) : la 2ᵉ fois, changed=0. Rien à faire = rien n'est touché. 👁 observe —
2 Le flux déclaratif Édite le plan (un serveur dans la GUI), ⚙ Appliquer le plan (instancier), puis Vérifier (dry-run) : tu prévisualises avant d'appliquer. 👁 observe —
3 La réversibilité git diff / git checkout sur le plan : l'état est du code, donc annulable. 👁 observe —
4 Casse & répare Modifie à la main un fichier géré par un rôle (ex. un .conf), puis redéploie : Ansible rétablit l'état voulu (le code gagne sur la dérive manuelle). Tu sens que la source de vérité, c'est le code. 🔨 casse-répare —

Source : Infra as Code & idempotence · § À toi de jouer.

La preuve — prouver, pas affirmer

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Produis une preuve make prouver (voûte exportée). Lis docs/audit/preuve-.md : chaque preuve, son verdict, l'affirmation couverte. 👁 observe —
2 Fais échouer une preuve — exprès Introduis un hôte fantôme : dans applications.yml, pointe une appli vers un hôte qui n'existe pas dans serveurs.yml. make prouver : P06 échoue, en nommant l'hôte. Corrige (ou via le de la GUI) : vert. 👁 observe P06
3 Une autre Remets de l'adressage dans une nomenclature (vlan: 42), make prouver : P20 échoue. Retire-le : vert. 👁 observe P20
4 Lis le registre Ouvre docs/audit/affirmations.md : trouve une affirmation ⚪ (non prouvable localement) — vois comment elle est assumée comme intention, jamais présentée comme prouvée. 👁 observe —
5 Comprends la valeur Demande-toi : quelle promesse est-ce que je fais sans preuve ? C'est exactement ce que ce registre force à regarder en face. 👁 observe —

Source : La preuve — prouver, pas affirmer · § À toi de jouer.

Le GUI (console d'exploitation)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Lance-la make inventaire-ui, ouvre l'URL affichée. Repère l'inventaire actif et l'état de la flotte (en haut), les onglets, « Appliquer le plan », « Sauvegarder ». 👁 observe —
2 Édite → prévisualise Vue Serveurs, change la mémoire d'un hôte, Sauvegarder, Appliquer le plan, puis Vérifier (dry-run) : tu vois ce qui changerait avant d'agir. 👁 observe —
3 Répare un hôte fantôme (l'erreur impossible) Si une appli pointe un hôte inexistant, ouvre la vue Applications, sélectionne-la : le « Hôte » ne montre que des hôtes réels. Choisis le bon, Sauvegarder, Appliquer. Tu ne peux pas re-saisir le fantôme. 👁 observe —
4 Bascule d'instance Vue Réseau, bouton « Activer » sur une autre instance. Toutes les vues suivent, sans redémarrer. 👁 observe —
5 Sens le garde-fou Essaie de sauvegarder un plan incohérent (ex. une base dont le consommateur n'existe pas) : la console refuse avec une raison. L'invalide ne passe pas. 👁 observe —
6 Casse & répare Édite hosts.yml à la main, reviens dans la GUI, « Appliquer le plan » : ta modification est écrasée par le plan. La source de vérité, c'est le plan — pas l'inventaire. 🔨 casse-répare —

Source : Le GUI (console d'exploitation) · § À toi de jouer.

Le plan & l'adressage dérivé

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Observe la dérivation Vue Serveurs de la GUI : chaque carte montre VMID · IP · VLAN. Aucun n'a été saisi — tous viennent du index. Note l'IP d'un hôte. 👁 observe —
2 Change le seed, regarde tout suivre Panneau Intrants → Réseau, change index (ex. de 1 à 7), « Appliquer le plan ». Toutes les IP basculent de 10.11.x à 10.17.x, les VLAN de 101x à 107x — d'un seul chiffre. Puis remets ta valeur. 👁 observe —
3 Sens la source unique make instancier (diff), puis make instancier-appliquer : « DIFF VIDE : le plan reproduit exactement l'inventaire » — le plan est la vérité. 👁 observe —
4 Casse & répare Édite hosts.yml à la main (change une IP). Relance make instancier : il signale l'écart. Ré-applique : le plan écrase ta modification. Tu sens que hosts.yml n'est pas la vérité — le plan l'est. 🔨 casse-répare —
5 Éprouve le garde-fou Ajoute une ligne supernet: 10.99.0.0/16 dans une nomenclature, puis make prouver : P20 échoue (« adressage stocké »). Retire-la : vert. La règle se prouve. 👁 observe P20

Source : Le plan & l'adressage dérivé · § À toi de jouer.

Le réseau des tenants — du câble au VRF

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Lis ton réseau physique : make underlay. Repère les VLAN sous 1000 (l'underlay) et les MTU. Pourquoi le transport doit-il être à 1500 quand l'overlay est à 1450 ? 👁 observe —
2 Regarde sans écrire : make sdn-plan. Si le cluster dit déjà ce que le plan dit, la sortie tient en une ligne. 👁 observe —
3 Trouve la sortie d'un tenant : dans make devis-sdn, repère la strophe FRR et l'adresse du prochain saut. À quel équipement appartient-elle ? 👁 observe —
4 Change index dans un modèle (jamais en production) et régénère : combien de valeurs ont bougé ? C'est la mesure exacte de ce que la dérivation t'épargne. Pour aller plus loin : docs/sdn-evpn.md (référence technique), Le plan & l'adressage dérivé, Multi-instance & f… 👁 observe —

Source : Le réseau des tenants — du câble au VRF · § À toi de jouer.

Liaisons (bindings)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Lis une liaison Ouvre instance/plan/applications.yml : une app avec expose: (liaison app→domaine), et serveurs.yml : un nœud avec integrations: (liaison nœud→service). 👁 observe —
2 Vois-la se résoudre Après make instancier, regarde l'inventaire généré : la cible est devenue une valeur concrète (FQDN, groupe) — le moteur a câblé. 👁 observe —
3 Requise vs optionnelle Compare : retirer client_journal d'un nœud → aucun problème (optionnelle). Déclarer une base sans serveur → make instancier/la validation échoue (requise). Tu sens la différence de modalité. 👁 observe —
4 Casse & répare Casse une liaison requise (ex. réfère une base à un serveur inexistant), relance l'instanciation : échec clair avant tout déploiement. Corrige : ça passe. Le moteur attrape le câblage manquant à ta place. 🔨 casse-répare —

Source : Liaisons (bindings) · § À toi de jouer.

Multi-instance & fédération

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Vois la flotte make instances : l'active (★), les index, les VLAN, le statut fédéré/local. Repère qui est en production. 👁 observe —
2 Bascule GUI, vue Réseau, bouton « Activer » sur une autre instance (ou make instance-utiliser NOM=…). Toutes les vues suivent — sans redémarrer. 👁 observe —
3 Crée une instance make instance-modeles (les modèles dispo), puis make instance-creer NOM=OPS-Test MODELE=socle INDEX=4. Un écosystème neuf, en une commande. 👁 observe —
4 Éprouve le garde-fou de collision Essaie de créer une instance avec un index déjà pris : refus avant toute copie. Puis make prouver → P21 veille sur la fédération. 👁 observe P21
5 Casse & répare Donne à deux instances fédérées le même index (édite une nomenclature), make instances : la bannière de collision s'allume ; make prouver : P21 échoue. Corrige l'index : tout redevient vert. 🔨 casse-répare P21
6 (Avancé) Promeus un produit Une instance qui tourne et se prouve peut devenir un modèle vendable : make model-creer MODE=instance SOURCE=OPS-… NOM=… — elle est généralisée (identité → exemple.*, secrets retirés) et validée. 👁 observe —

Source : Multi-instance & fédération · § À toi de jouer.

Métriques & journaux

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Interroge les métriques (sur obs-01) — combien de nœuds scrapés, tous UP ? « commande » 👁 observe —
2 Vois les journaux : curl -s http://localhost:3100/loki/api/v1/label/host/values → les nœuds qui expédient leurs logs. 👁 observe —
3 Ouvre Grafana (https://grafana.lab.chezlepro.internal) — métriques et logs au même endroit. 👁 observe —
4 Casse & répare Arrête prometheus-node-exporter sur un nœud : dans Prometheus, sa cible passe up=0 (DOWN). Redémarre : elle repasse UP. Tu sens que c'est l'agent qui nourrit le serveur (modèle pull). 🔨 casse-répare —

Source : Métriques & journaux · § À toi de jouer.

PKI & confiance

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Regarde un certificat Sur un nœud avec client_pki : « commande » Repère le sujet (l'identité), l'émetteur (l'intermédiaire) et la validité. 👁 observe —
2 Suis la chaîne de confiance « commande » OK = la racine valide bien le certificat du serveur. C'est ① en action. 👁 observe —
3 Vois-le servir en vrai Le LDAPS d'OpenLDAP utilise ce certificat : « commande » 0 (ok) = confiance vérifiée. 👁 observe —
4 Casse & répare Retire la racine du magasin système, refais un curl HTTPS interne : avertissement de certificat (plus de confiance). Réinstalle la racine : ça remarche. Tu viens de sentir pourquoi « faire confiance à la racine » est la clé de voûte. 🔨 casse-répare —

Source : PKI & confiance · § À toi de jouer.

Reverse-proxy & TLS

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Route par nom Deux noms, un seul edge (192.168.15.21) : « commande » Change grafana en forge : même IP, backend différent. C'est le routage par SNI. 👁 observe —
2 Vois la terminaison TLS Le certificat présenté est celui de l'edge (avec les SAN des exposés) : openssl s_client -connect 192.168.15.21:443 -servername grafana.lab… | openssl x509 -noout -text | grep -A1 'Subject Alternative'. 👁 observe —
3 Casse & répare Arrête le backend (ex. systemctl stop grafana-server sur obs-01) et rouvre Grafana : l'edge répond 502 Bad Gateway (le proxy est là, le service non). Redémarre : ça remarche. Tu distingues le proxy de ce qu'il sert. 🔨 casse-répare —

Source : Reverse-proxy & TLS · § À toi de jouer.

Sauvegardes (3-2-1)

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Lance une sauvegarde Sur un nœud avec client_backup : « commande » 👁 observe —
2 Liste les instantanés (le dépôt vit hors-nœud) : « commande » 👁 observe —
3 Restaure — le vrai test Restaure dans un dossier temporaire et compare : « commande » (sur infra-pki-01 ; ailleurs, compare le dump correspondant.) 👁 observe —
4 Casse & répare Supprime un fichier de donnée (une copie de test !), restaure-le depuis l'instantané, vérifie qu'il est identique. Tu viens de sentir que la valeur d'une sauvegarde est la restauration, pas la sauvegarde. 🔨 casse-répare —

Source : Sauvegardes (3-2-1) · § À toi de jouer.

Supervision & impact

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Ouvre Icinga Web 2 (https://icinga.lab.chezlepro.internal, via le SSO) : la liste des hôtes et services supervisés, avec leur état (vert/jaune/rouge). 👁 observe —
2 Vois l'impact Menu Business Processes → « Supervision Chezlepro » : un processus qui agrège des checks (load, procs, ping…) en un état roulé. C'est l'impact, pas une case. 👁 observe —
3 Casse & répare Provoque l'échec d'un check (ex. arrête un service surveillé) : l'état passe CRITICAL, et le processus BPM qui en dépend rougit (l'impact remonte). Répare : tout reverdit. Tu sens la différence entre mesurer et superviser/alerter. 🔨 casse-répare —

Source : Supervision & impact · § À toi de jouer.

Sécurité & durcissement

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Constate les couches (sur n'importe quel nœud) : « commande » 👁 observe —
2 Moindre privilège : PermitRootLogin est à no, l'accès se fait par le compte ansible + clé SSH. Vérifie : sshd -T | grep -E 'permitrootlogin|passwordauthentication'. 👁 observe —
3 Casse & répare (avec prudence, en lab) Assouplis un réglage sysctl, observe, puis remets-le. Tu sens que chaque ligne de durcissement ferme une porte précise. 🔨 casse-répare —

Source : Sécurité & durcissement · § À toi de jouer.

Virtualisation & clonage

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 Regarde un clone Dans la GUI (make inventaire-ui), un serveur actif a été cloné du template (bouton « 🖥 Créer la VM »). Son VMID/IP sont dérivés de la nomenclature. 👁 observe —
2 Vois l'identité cloud-init Sur un nœud : cloud-init query hostname, hostname -f, et l'agrandissement du disque racine (df -h /). 👁 observe —
3 Sépare les deux couches cloud-init a posé l'identité ; tout le reste (paquets, services, durcissement) vient d'Ansible. Le template, lui, ne contient aucune donnée de clone. 👁 observe —
4 Casse & répare (mentalement + lab) Supprime un nœud non critique et reclone-le depuis le template, puis redéploie : il revient à l'identique. Tu sens que la machine est reconstructible. 🔨 casse-répare —

Source : Virtualisation & clonage · § À toi de jouer.

Vérifier le déployé — quand la preuve statique ne suffit plus

# Ce qu'on éprouve Le geste (avec l'attendu) Type Preuve auto
1 — Lance les cinq devis sur ta flotte. Note le temps que ça prend : quelques minutes pour ce qui demandait une journée d'enquête à la main. 👁 observe —
2 Casse quelque chose exprès — arrête un service publié, change un port — et relance le devis concerné. S'il ne dit rien, c'est lui qu'il faut réparer, pas le service. 👁 observe —
3 — Cherche, dans ton propre outillage, une vérification qui n'a jamais échoué. Demande-toi si c'est parce que tout va bien, ou parce qu'elle ne regarde rien. | Terme | Ce que tu retiens | | | | | preuve statique | lit le code ; rapide, univ… 👁 observe —

Source : Vérifier le déployé — quand la preuve statique ne suffit plus · § À toi de jouer.