ADR-051 : Insertion d'une méthode dans le contrôleur des pages publiques¶
Statut¶
Proposé, Forge 1.0.0-beta.17 (ticket ARCH-USER-CONTROLLER-REWRITE-ADR-001).
ADR distinct annoncé par l'ADR-030, qui a
explicitement laissé hors de son périmètre la réécriture in-place d'un
contrôleur utilisateur (« question distincte, à trancher séparément, principe
4 »). Tant que cet ADR n'est pas accepté par le mainteneur, le comportement
décrit reste celui livré, sans modification de la charte.
Date¶
2026-06-26
Contexte¶
forge make:public-page <Nom> génère une page publique : un template, une route
(via le mécanisme d'injection cadré par l'ADR-030) et une méthode de
contrôleur. Cette dernière est posée par _ensure_controller_method
(cli/public/public_page.py), qui écrit dans
mvc/controllers/public_pages_controller.py, un fichier sous contrôle de
l'utilisateur.
Trois cas se présentent :
- Fichier absent : Forge crée
public_pages_controller.pyavec la classe
PublicPagesControlleret la méthode. C'est une écriture write-if-new,
conforme au principe 9 (création d'un fichier nouveau). - Méthode déjà présente : un test (
def <méthode>() détecte la méthode ;
Forge ne touche à rien. Comportement idempotent. - Fichier présent sans la méthode : Forge insère la méthode dans la
classePublicPagesControllerexistante. L'insertion repère la fin de la
classe par analyse AST (ast.parse,ClassDef.end_lineno), insère le
bloc de méthode, puis réécrit le fichier.
Le cas 3 est une modification in-place d'un fichier sous contrôle
utilisateur, ce que le principe 4 (préserver le code utilisateur) et le
principe 9 (pas d'écriture invisible) encadrent strictement. C'est le point que
l'ADR-030 a renvoyé à un ADR dédié.
Garde-fous déjà présents dans le code livré :
- Explicite : l'écriture résulte d'une commande tapée par l'utilisateur
(make:public-page), jamais d'un autre flux. - Idempotent : la présence de la méthode est détectée avant insertion (cas
2), ré-exécuter ne duplique pas. - Fail-safe : si le fichier ne parse pas (
SyntaxError) ou si la classe
PublicPagesControllerest absente, Forge n'écrit pas et renvoie un
avertissement invitant à compléter le contrôleur manuellement. - Ciblé : l'insertion ne vise qu'un fichier et une classe de nom
conventionnel Forge (public_pages_controller.py/PublicPagesController),
jamais un contrôleur métier arbitraire. - Annoncé :
make_public_pagerenvoie un résultat (controller_changed,
avertissement éventuel) affiché à l'utilisateur.
Limite assumée : si l'utilisateur a écrit lui-même une classe
PublicPagesController dans ce fichier conventionnel, Forge y insérera quand
même la méthode. Le nom est conventionnel et le fail-safe couvre les cas
ambigus, mais l'écriture reste in-place.
Décision (proposée)¶
Acter le comportement du cas 3 comme conforme, en étendant au seul
contrôleur des pages publiques les quatre conditions de l'ADR-030 (explicite,
idempotent, délimité/visible, annoncé), renforcées par deux garanties propres au
code utilisateur :
- Fail-safe : aucune écriture si le fichier ne parse pas ou si la classe
cible est absente ; un avertissement oriente vers une complétion manuelle. - Ciblé sur un nom conventionnel Forge : seul
mvc/controllers/public_pages_controller.py/PublicPagesControllerest
modifié, jamais un contrôleur métier arbitraire.
La charte (principe 4) sera précisée, après validation du mainteneur, pour
distinguer la réécriture in-place silencieuse et arbitraire (interdite) de
l'insertion explicite, idempotente, fail-safe et ciblée sur un fichier
conventionnel généré par Forge (autorisée pour make:public-page).
Conséquences¶
make:public-pageconserve sa valeur (câbler une page publique d'un geste)
sans dégrader l'UX vers un mode « affichage » pur.- Le périmètre reste étroit : aucune autre commande n'est autorisée à modifier
in-place un contrôleur ; les contrôleurs métier restent intouchables. - Un test de garde-fou pourra verrouiller les invariants (fail-safe sur fichier
non parsable, idempotence, ciblage surPublicPagesController).
Alternatives écartées¶
- Re-scoper
make:public-pageen mode affichage (commemake:crud) :
respecterait le principe 4 à la lettre mais imposerait à l'utilisateur de
coller la méthode lui-même, dégradant une commande dont la valeur est le
câblage d'un geste. Corriger ce symptôme plutôt que préciser la portée du
principe 4 contredit la règle d'évolution A (retirer la cause, pas le
symptôme). - Laisser la contradiction implicite : expose à un reproche d'audit
récurrent sur un principe non négociable, comme c'était le cas avant
l'ADR-030.
Référence¶
- ADR-030 : injection de routes par commande
explicite, qui a renvoyé ce point à un ADR distinct. cli/public/public_page.py(_ensure_controller_method).- Charte :
CHARTE_DOC.md(principe 4, préserver le code utilisateur ; principe
9, pas d'écriture invisible ; règle d'évolution A).