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 classePublicPagesControlleret 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 classe
PublicPagesControllerexistante.
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 classePublicPagesControllerest 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 sur
PublicPagesController).
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).