P31 : le motif laissait passer toute cible contenant une majuscule

« Pourquoi pas make myDay ? » — la cible existe (alias strict de reconstruire)
mais n'avait aucun texte d'aide, et P31 la declarait conforme. Le motif etait
^[a-z][a-z0-9_-]*: — toute majuscule echappait au controle. myDay est citee
dans l'aide du Makefile et dans la GUI, et n'apparaissait dans aucun
recensement.

Une preuve ne vaut que ce que vaut son motif. Celle-ci a ete ecrite avec la
conviction d'etre rigoureuse et testee dans les deux sens le jour meme. Le
trou a ete trouve par une question, pas par un test.

Troisieme fois sur la meme preuve en une journee, apres le rapport genere qui
se citait lui-meme et l'inventaire genere qui l'aurait satisfaite par
construction. La difficulte n'est pas d'ecrire un test, c'est de delimiter
honnetement ce qu'il regarde.

87 cibles documentees, 36 scripts, 54 roles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-08 14:34:00 -04:00
parent a430edf014
commit 872d590031
4 changed files with 30 additions and 4 deletions

View file

@ -1,5 +1,26 @@
# CHANGELOG — Set-OPS
## 2026-08-08 — Une question de l'exploitant trouve un trou dans P31, une heure après
« Pourquoi pas `make myDay` ? » — la cible existe, c'est un alias strict de
`reconstruire`. Mais elle n'avait **aucun texte d'aide**, et P31 la déclarait conforme.
Le motif était `^[a-z][a-z0-9_-]*:` : **toute cible contenant une majuscule échappait au
contrôle.** `myDay` est citée dans l'aide du Makefile et dans la GUI ; elle n'apparaissait
dans aucun recensement. Corrigé en `^[A-Za-z][A-Za-z0-9_-]*:`, et l'aide posée.
Ce n'est pas un détail sur une cible. **Une preuve ne vaut que ce que vaut son motif**
et celle-ci a été écrite avec la conviction d'être rigoureuse, testée dans les deux sens le
jour même, et elle laissait quand même passer un cas. Le trou n'a pas été trouvé par un
test mais par quelqu'un qui a demandé « et celle-là ? ».
À ranger à côté des deux critères creux de P31 (le rapport généré qui se citait lui-même,
et l'inventaire généré qui aurait satisfait le critère par construction). Trois fois sur la
même preuve, en une journée : la difficulté n'est pas d'écrire un test, c'est de délimiter
honnêtement ce qu'il regarde.
Compte après correction : **87 cibles documentées, 36 scripts, 54 rôles**.
## 2026-08-08 — `make raser` : la seule commande destructive du moteur
Ajoutée pour rendre la reconstruction from-zero **répétable** — un test qu'on ne peut jouer

View file

@ -599,7 +599,7 @@ reconstruire: _instance-requise ## Reconstruit un ecosysteme depuis zero : VM pu
# « Go ahead, make my day. » — LE bouton rouge : alias de reconstruire (Clint Eastwood).
# Cree toutes les VM puis deploie tout, en une commande. Garde CONFIRMER=true.
.PHONY: myDay
myDay: reconstruire
myDay: reconstruire ## Alias strict de `reconstruire` (meme cible, memes gardes)
deployer-groupe: ## Deploie un seul groupe sur toute la flotte — GROUPE=<groupe>
@if [[ -z "$(GROUPE)" ]]; then \

View file

@ -43,7 +43,7 @@
| P28 | Pools Proxmox : un par tenant, sans collision | AFF-110 | ✅ OK | CONFORME : 2 pool(s) Proxmox, 28 VM placee(s), aucun nom ni VMID en collision. |
| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 23 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 12, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv |
| P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 2 zone(s), 12 VNet(s), 12 sous-reseau(x), aucune collision. |
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 36 scripts expliques et atteignables, 86 cibles make documentees, 54 roles avec README. |
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 36 scripts expliques et atteignables, 87 cibles make documentees, 54 roles avec README. |
## Couverture des affirmations ✅ du registre

View file

@ -466,7 +466,12 @@ def preuve_documentation_outillage() -> tuple[bool, str]:
muettes = [
ligne.split(":")[0]
for ligne in makefile.splitlines()
if re.match(r"^[a-z][a-z0-9_-]*:", ligne) and "##" not in ligne
# `[A-Za-z]` et non `[a-z]` : le premier motif laissait passer TOUTE cible
# contenant une majuscule. `myDay` — alias de `reconstruire`, cite dans l'aide
# et dans la GUI — echappait donc au controle et n'avait aucun texte d'aide.
# Trouve par une question de l'exploitant, une heure apres l'ecriture de P31 :
# une preuve ne vaut que ce que vaut son motif.
if re.match(r"^[A-Za-z][A-Za-z0-9_-]*:", ligne) and "##" not in ligne
]
if muettes:
manques.append(f"{len(muettes)} cible(s) make sans texte d'aide `##` : "
@ -482,7 +487,7 @@ def preuve_documentation_outillage() -> tuple[bool, str]:
if manques:
return False, " | ".join(manques)
n_c = len([l for l in makefile.splitlines() if re.match(r"^[a-z][a-z0-9_-]*:", l)])
n_c = len([l for l in makefile.splitlines() if re.match(r"^[A-Za-z][A-Za-z0-9_-]*:", l)])
n_r = len([d for d in (RACINE / "roles").iterdir() if d.is_dir()])
return True, (f"{len(scripts)} scripts expliques et atteignables, "
f"{n_c} cibles make documentees, {n_r} roles avec README.")