Chapitre 6 / 39
Trois principes de conception
Trois principes traversent chaque décision d’outillage et de câblage dans le reste de ce manuel. Ce sont eux qui expliquent pourquoi la stack a cette forme, et pourquoi certaines alternatives évidentes ont été écartées. Un lecteur qui ne lit que ce chapitre comprend pourquoi le système est ainsi conçu.
Statut : En ligne — tous les chapitres à partir d’ici sont écrits selon ces trois principes. Si un chapitre ultérieur semble en contredire un, le principe l’emporte et le chapitre est faux.
Principe 1 — Fork conceptuel plutôt qu’adoption upstream
Quand Sodimo a besoin d’une capacité qu’un projet open source fournit déjà, la démarche par défaut est de lire le projet upstream, comprendre ce qu’il fait, et écrire une version réduite qui couvre uniquement ce que Sodimo utilise. La démarche par défaut n’est pas de récupérer l’image container upstream et de la faire tourner telle quelle.
La raison, c’est la remise de mission. Une fois l’engagement terminé, Sodimo n’a pas d’ingénieur à plein temps. Chaque changement cassant upstream entre ce moment et le jour où quelqu’un est recruté devient une dette — une migration de schéma surprise, un changement de format de config, une variable d’environnement supprimée, un chemin d’auth déprécié. Un container qui suit :latest finira par casser et personne ne sera là pour le réparer. L’objectif à la remise est une stack fonctionnelle et statique : l’équipe recrute un ingénieur de manière délibérée, pas en urgence.
Comment ce principe se concrétise :
- Des versions épinglées partout. Si la stack utilise une image upstream, le quadlet épingle un tag précis. Le calendrier de sorties upstream n’est pas le calendrier de mises à jour de Sodimo.
- Réduire le périmètre agressivement. Là où upstream a vingt fonctionnalités, le build Sodimo livre les trois que Rani, Paul et Michel utilisent vraiment. Moins de fonctionnalités, moins de façons de casser.
- Pas de synchronisation continue. Un snapshot à une version connue et stable est vendorisé et possédé à partir de là.
Le CRM est l’application canonique : un CRM TypeScript fait maison sur Cloudflare, inspiré de Twenty et Pipedrive — ni un fork de Twenty, ni un Pipedrive self-hosted. Sodimo possède le code. La stack mail (Postfix, Dovecot, rspamd, Piler) est le contre-exemple où l’adoption upstream est sûre — OSS vieux de plusieurs décennies, robuste, aucun scope-down requis.
Le test pour tout futur composant : « si l’ingénieur disparaît et que l’upstream livre un changement cassant le mois prochain, est-ce que quelque chose chez Sodimo casse ? » Si oui, réduire le périmètre et prendre possession du code.
Principe 2 — Comptabilité des tokens sur chaque exécution
Chaque invocation IA dans la stack Sodimo émet un enregistrement d’usage vers un seul registre append-only. Quelle que soit la surface — chat interactif, agent planifié, réponse automatique par email, appel d’outil MCP — la stack peut à tout moment produire la liste complète : chaque token que l’IA de Sodimo a consommé, en local comme dans le cloud, quand, pourquoi et par qui.
La raison, c’est la démonstration des économies. Le cœur économique de l’engagement est que l’IA locale économise de l’argent par rapport à l’IA cloud. Cette affirmation n’est valide que si elle peut être prouvée. Sans comptabilité de bout en bout, la stack a une anecdote, pas un chiffre. Le registre est aussi un actif de données à long horizon : il dit aux futurs ingénieurs, et plus largement au secteur, exactement quand l’IA locale est rentable à l’échelle d’une PME.
Chaque exécution produit une ligne. Schéma minimum :
run_id,ts,surface(openwebui, paperclip, email_autoreply, mcp_tool, eval, other)user_id,agent_id(null pour les exécutions de service)model,provider(local_llamacpp, anthropic, other)tokens_in,tokens_out,tokens_cachedlatency_ms,outcome(success, error, timeout, refused)cost_eur— coût réel (zéro pour les exécutions locales, calculé à partir de la tarification du fournisseur pour le cloud)cost_eur_if_cloud— le contrefactuel : ce qu’aurait coûté cette exécution sur un modèle cloud haut de gamme
Le champ cost_eur_if_cloud est celui qui porte le récit. Chaque exécution locale reçoit à la fois un coût réel (~0 €) et le coût qu’elle aurait eu dans le cloud. Cumulé sur toutes les surfaces, contrefactuel moins réel donne le chiffre des économies sur le tableau de bord.
Le registre vit dans D1, dans une table appelée run_ledger. Il est append-only, horodaté, interrogeable par surface/modèle/utilisateur/date, et exportable en CSV pour l’étude. Un tableau de bord au niveau du chapitre sur le site changelog expose les trois chiffres phares : tokens consommés, coût réel, coût contrefactuel, économies.
Chaque nouveau quadlet, chaque nouvel outil MCP, chaque nouvelle compétence répond à une question avant d’être mis en production : « comment ceci émet-il un enregistrement d’exécution ? » Si la réponse est « ça ne le fait pas », le composant n’est pas prêt.
Le local est le défaut ; le cloud est une escalade. La règle de routage qui rend le chiffre des économies significatif : chaque invocation IA part par défaut sur la stack llama-swap on-prem (local-task pour le chat et l’usage d’outils, local-heavy pour le raisonnement, local-coder pour le code). Le cloud (Claude Opus via l’alias cloud-heavy) est opt-in à chaque invocation, pas le point de départ. Démarrer sur Opus et redescendre vers le local inverse l’économie du registre. Un commentaire Fattal quotidien atterrit sur local-heavy par défaut ; une revue de contrat juridique nécessitant Claude Opus est explicitement marquée dans l’invocation d’outil (escalate: "cloud-heavy"). Le registre capture les deux : cost_eur est 0 pour les exécutions locales, cost_eur_if_cloud enregistre le contrefactuel. Ce delta est le chiffre des économies. Voir ch41 IA on-prem pour l’énumération complète des déclencheurs d’escalade et la surface du compteur d’utilisation (D-188, D-189).
Pointer. → ch36 OpenWebUI et ch42 Outils MCP pour les sites d’émission ; ch41 IA on-prem pour la politique d’escalade ; ch55 D-179 pour le verrouillage de schéma, D-188 pour le routage local-first, D-189 pour le compteur d’utilisation.
Principe 3 — Cloudflare est la surface MCP unique
La stack Sodimo a exactement un endpoint MCP : un Cloudflare Worker appelé sodimo-core, fronté par Cloudflare Access avec Google Workspace comme fournisseur d’identité. Il n’y a pas de serveur MCP on-prem. Les services tournant sur le harness de Gennevilliers sont accessibles de deux façons :
- Les humains utilisent l’interface native de chaque service via Tailscale. OpenWebUI pour le chat en modèle local. L’interface web de Piler pour l’archive email. Cockpit pour l’administration serveur.
- Le code atteint le harness via un câblage pull-based. Le Worker écrit dans une Cloudflare Queue. Un petit service systemd sur le harness interroge la queue et agit sur les messages. Le harness n’expose aucun port entrant pour ce trafic.
La raison est triple.
L’inventaire MCP on-prem s’est révélé vide. En parcourant la liste des candidats — recherche Piler, admin rspamd, accès au filesystem, llama.cpp, transcription vocale, agent computer-use — chacun a soit un meilleur chemin (interface humaine via Tailscale, admin via SSH, wrapper UI comme OpenWebUI) soit est hors périmètre pour cet engagement. Il n’existe aucun outil qui doive tourner on-prem pour des raisons de gravité des données, être appelable par un agent (pas un humain), et ne puisse être satisfait par une pull-queue.
Une surface unique évite un bug connu de Claude.ai. Le handshake OAuth entre Claude.ai et des serveurs MCP self-hosted derrière un tunnel se termine actuellement mais abandonne le token bearer lors des requêtes suivantes. La solution recommandée est de fronter le serveur avec Cloudflare Access — ce qui équivaut à ne pas avoir de serveur MCP self-hosted du tout. Une architecture pure-Cloudflare contourne cette famille de bugs.
L’outillage de gateway MCP est trop jeune pour être adopté statiquement. Aucun agrégateur sur le marché 2026 n’est complet fonctionnellement, et la catégorie sera différente dans un an. Faire tourner un gateway upstream récent sur le harness est exactement ce contre quoi le Principe 1 met en garde. Ne pas en faire tourner du tout est strictement plus sûr.
L’exemple canonique est l’envoi d’email. Le Worker expose un outil email_send. Quand Claude.ai ou un agent l’appelle, le Worker écrit le payload dans une queue appelée email_outbox. Un petit service Python sur le harness interroge la queue toutes les quelques secondes, valide contre une liste blanche d’expéditeurs, passe à Postfix, et acquitte. Le harness n’ouvre aucun port ; le Worker n’appelle pas le harness ; si le harness est hors ligne, les messages sont mis en queue jusqu’à son retour.
La même forme s’applique symétriquement à tout ce qui tourne sur le harness. Les agents Paperclip ne prennent pas de raccourci vers le sendmail local même si c’est techniquement possible — ils appellent l’outil Worker email_send exactement comme Claude.ai le fait. Fedora → Cloudflare → Fedora est une fonctionnalité, pas un coût. Quatre propriétés en dépendent : un registre d’exécution unifié, une politique d’autorisation d’expéditeur unique, un schéma d’observabilité commun, et un rate-limiting centralisé avec une dead-letter queue. Chacune est définitivement perdue si un producteur contourne le Worker.
La co-localisation physique est un fait, pas une autorisation architecturale de court-circuiter le contrat.
Comment les trois interagissent
Les trois principes se renforcent mutuellement.
Le Principe 1 (posséder le code) rend le Principe 2 (émettre un enregistrement d’exécution) naturel : si Sodimo possède le code, l’émission est intégrée dès le départ. Adopter des outils upstream signifierait suivre le format de reporting d’utilisation upstream à travers les changements cassants.
Le Principe 3 (une surface MCP) rend le Principe 2 applicable : chaque effet de bord piloté par l’IA passe par le Worker, qui est l’endroit où l’écriture dans le registre se produit. Un agent qui contourne le Worker produit une exécution invisible.
Le Principe 1 (posséder) et le Principe 3 (une surface) ferment la boucle sur l’outillage de gateway : la seule raison plausible d’adopter un outil upstream récent sur le harness serait un gateway MCP, et le Principe 3 dit qu’il n’y a aucun travail à lui confier.
Ces trois principes sont la colonne vertébrale. Le reste du manuel montre comment ils s’appliquent au matériel réel, au code réel, et aux personnes réelles.