Aller au contenu
Mocky/Docs v0.2
Architecture

ADR 001 — Muse : une intelligence du design pilotée par MCP

35 min de lecture
Pourquoi c’est ainsi

Une décision déjà livrée survit dans le code, mais son raisonnement, non : les options pesées puis écartées ne laissent de trace nulle part. Un Architecture Decision Record (ADR) — une note datée, à laquelle on ajoute sans jamais réécrire, portant sur un seul choix, son contexte et ses conséquences — existe pour qu'un lecteur ultérieur distingue une contrainte délibérée d'un accident. Celui-ci est numéroté et limité à un seul sujet, parce qu'un document qui veut tout couvrir finit remanié au point de ne plus décrire aucun moment précis.

  • Statut : Accepté — implémenté sur main (phases 1–5 ; il reste quelques finitions d'interface de la phase 4 et le profil de goût via le MCP mémoire, voir §8/§9)
  • Date : 2026-07-26
  • Remplace / se rapporte à : le registre de capacités existant, le planificateur, le pont DESIGN.md et le proxy de fournisseur.
  • Origine : MOCKY_MUSE_PROMPT.md (« Prompt G », rédigé par Claude Fable 5).

Cet ADR est le livrable de la phase 0. Il consigne ce qu'est réellement la base de code actuelle, les endroits où les hypothèses du plan Muse s'en écartent, les décisions concrètes que nous allons prendre, et la manière dont chaque invariant existant ainsi que les nouveaux invariants de la série M sont respectés. Aucun code d'implémentation n'est écrit à cette phase. L'implémentation ne commence qu'à la phase 1, une fois cet ADR approuvé.


1. Contexte — ce qu'est réellement Mocky aujourd'hui#

Pourquoi c’est ainsi

Toutes les décisions qui suivent dépendent du lieu où le code s'exécute réellement, et le document commence donc par l'établir : le plan Muse supposait un pipeline côté serveur, alors que Mocky construit en fait les écrans dans l'onglet du navigateur (src/lib/generate.ts, src/lib/plan.ts, src/lib/capabilities/select.ts) et garde un serveur mince. Énoncer cet écart avant de rien décider est ce qui rend la suite vérifiable — un lecteur peut contrôler la prémisse et pas seulement la conclusion, et une prémisse fausse ici invaliderait silencieusement les dix décisions.

Le schéma d'architecture du prompt Muse (§2) décrit un pipeline centré sur le backend : MCP Host → Inspiration Engine → Dossier → Planner → Generation, le tout à l'intérieur d'un « Mocky Backend (Node/Express) ». Ce n'est pas ainsi que Mocky est bâti. Le constat d'audit le plus important à lui seul est le suivant :

Le pipeline de génération de Mocky s'exécute dans le navigateur, pas dans le backend.

Concrètement :

AspectOù cela vit aujourd'huiFichier(s)
Sélection des capacités (déterministe)Navigateursrc/lib/capabilities/select.ts
Planificateur (optionnel, LLM à sortie structurée)Navigateursrc/lib/plan.ts
Génération / édition / correction (en flux)Navigateursrc/lib/generate.ts
Orchestration du pipeline + phases d'étapeNavigateur (React)src/components/ProjectView.tsx
Pont DESIGN.md (préambule, jetons, export)Navigateursrc/lib/design.ts, designTokens.ts, export/theme.ts, export/project.ts
Rendu en bac à sable (iframe d'origine nulle, Babel vendorisé)Navigateursrc/components/Preview.tsx, lib/capabilities/prelude.ts
PersistancelocalStorage du navigateur (mocky.projects.v1, mocky.design.v1) ; les réglages, clé d'API comprise, ne quittent pas le navigateursrc/lib/project.ts, sync.ts
Rôle du backendMince : service des fichiers statiques, comptes/SSO, synchronisation JSON par utilisateur, et le reverse proxy /__provider protégé contre le SSRFserver/index.js, server/provider-proxy.js

Le backend est délibérément minimal : de simples fichiers JSON sous server/data/, aucune base de données, aucune dépendance native (express + cookie-parser, rien d'autre). Les écritures sont atomiques (fichier temporaire

  • renommage). Cette posture « pas de base, pas de dépendance native » est un invariant de fait du projet, et l'image Docker (node:20-slim) dépend de ce qu'elle reste petite.

Ce que cela implique pour Muse. Les parties de Muse qui ne peuvent pas tourner dans un navigateur — lancer des serveurs MCP locaux sur stdio, exécuter Playwright/Chromium, récupérer des pages web quelconques, télécharger et stocker des fichiers images — doivent vivre dans le backend Node. Muse introduit donc, pour la première fois, un vrai pipeline côté serveur et un ensemble non négligeable de nouvelles dépendances backend. C'est la tension centrale que cet ADR résout (voir la décision D3).

Deuxième conséquence : aujourd'hui l'application est pleinement utilisable en frontend seul (npm run dev, sans backend). Muse exige que le backend tourne. Quand le backend est absent (mode localStorage pur), l'interrupteur Muse doit être masqué ou désactivé avec un avertissement clair — il ne doit jamais donner l'illusion de fonctionner tout en ne faisant rien.


2. Les huit invariants existants, redits et vérifiés#

Pourquoi c’est ainsi

Un invariant est une règle que le code ne doit jamais enfreindre, et ceux de Mocky étaient cités par leur numéro dans des commentaires dispersés (generate.ts, plan.ts et capabilities/registry.test.ts disent tous « invariant N ») sans qu'aucun fichier ne les énumère, si bien que personne ne pouvait confronter un travail neuf à l'ensemble complet. Les rassembler ici fait passer « Muse ne casse rien » du statut d'affirmation à celui d'un tableau qu'un relecteur parcourt ligne à ligne, et c'est pourquoi la colonne de conformité est accolée à la règle plutôt que reléguée dans une note séparée.

Les invariants sont cités par leur numéro dans les commentaires du code (invariant 1/2/3/5/8) mais n'avaient jamais été réunis en un seul endroit. Cet ADR les codifie tous les huit (reconstitués à partir du code et de la liste entre parenthèses du prompt Muse lui-même) pour que la phase 1 et les suivantes puissent y être confrontées. Une partie de la valeur de cet ADR tient au simple fait de les écrire.

#InvariantPreuveConformité de Muse
I1Ne jamais analyser à l'expression régulière du code généré ou vendorisé pour « découvrir des noms » ou décider de ce qui est utilisé — passer par un vrai parcours de portées (Babel). (L'analyse de la prose Markdown est explicitement exemptée.)generate.ts:381, export/rewrite.ts:6, export/theme.ts:11Muse analyse du Markdown/JSON (dossier, DESIGN.md) et la sortie JSON du modèle — de la prose et des données, pas du code. Le plan d'imagerie (Imagery Plan) injecte les images par identifiant d'emplacement, jamais en réécrivant le JSX généré à l'expression régulière. ✅
I2L'iframe d'aperçu est d'origine nulle (sandbox="allow-scripts", sans allow-same-origin) ; les URL blob sont de même origine que null, donc aucun CORS n'est nécessaire. Ne jamais ajouter d'attribut crossorigin.Preview.tsx:62-64,149Les images générées sont servies depuis l'origine de Mocky et référencées en URL absolues, sans attribut crossorigin (l'affichage d'une n'est pas soumis au CORS). Voir D5. ✅ (nouvel invariant M6)
I3Aucun