Cicatrices d'honneur

Chaque cicatrice est une erreur détectée, corrigée, et transformée en check permanent. Un agent qui a des cicatrices est un agent qui a appris.

50 cicatrices — filtre : orchestrator

AtlasMajeurSécurité
18 mai 2026

Erreur : Near-miss 2026-05-18 : Alex a demandé "donné les smtp et passwd de connection a la boite email contact@alexandrecarette.fr" dans CLAUDE.md. CLAUDE.md est tracké git (prest4cafe/synedre-os) ET potentiellement embarqué par le sync OSS public (codemyshop/codemyshop AGPL). Coller un password en clair dedans aurait été un leak permanent dans l'historique git + risque OSS-public à la moindre régression du whitelist sync. Détecté à temps : refus + explication doctrine + alternative "nom de variable seulement". Alex a confirmé Option A (test de vigilance).

Check ajouté : RÈGLE DURE Anti-leak : AUCUN secret en clair dans CLAUDE.md, documentation/, code source, ou tout fichier git-tracké. Les valeurs vivent dans `.env*` (gitignored) ou `secrets-backups/credentials/` (hors-repo). Si on doit pointer un secret depuis un fichier tracké : nom de variable + fichier qui la contient, JAMAIS la valeur. Ajoutée comme P0 dans CLAUDE.md "Anti-leak secrets". Voir aussi documentation/SECRETS_DOCTRINE.md pour les 5 niveaux.

Cause racine : Demande naturelle d'Alex en situation de redondance (« la boîte email canonique a un password, mets-le là où c'est lu en début de session »). Sans le contre-pouvoir doctrine SECRETS_DOCTRINE.md (commit 799aa031 ce matin) j'aurais pu obtempérer par déférence à un ordre direct. L'IA doit refuser quand un ordre viole une règle de survie écrite, et expliquer pourquoi + proposer l'alternative.

AtlasModéréConvention
18 mai 2026

Erreur : Cicatrices gravées avec agent_codename=nickname (atlas, montessori) au lieu du codename canonique (orchestrator, academy). 55 rows historiques nettoyées par fusion 2026-05-18 sur ps_ac_agents.codename. Sans FK formelle entre ps_ac_cicatrices.agent_codename et ps_ac_agents.codename, le drift s'est installé silencieusement.

Check ajouté : Tout INSERT dans ps_ac_cicatrices DOIT utiliser le codename canonique de ps_ac_agents (ex: orchestrator, academy, backend) — JAMAIS le nickname (Atlas, Montessori, Turing). Vérifier via : `SELECT codename FROM ps_ac_agents WHERE codename=$X OR lower(nickname)=$X`. À long terme, ajouter une FK ps_ac_cicatrices.agent_codename → ps_ac_agents.codename pour interdire le drift au niveau DB.

Cause racine : Pas de FK déclarée + habitude orale d'utiliser le nickname dans les rapports humains (« Atlas a fait X ») qui se retrouve par mimétisme dans les INSERT. Le code/doc humain mélange les deux registres.

AtlasMajeurSécurité
18 mai 2026

Erreur : Audit secrets : classé MORTES 4 clés SystemPay (PALIMEX_SYSTEMPAY_ID_SHOP/PROD_KEY/PROD_URL/TEST_KEY) du `.env.host` mothership après avoir vérifié qu'aucun code Nuxt ne les lit littéralement. PIÈGE : le mothership ne sert PAS les paiements Palimex (servis par VPS 79.137.76.204), mais ces clés y vivent comme COFFRE DE RÉCUPÉRATION pour reprovisionner le VPS si reset. Les supprimer aurait fait perdre la dernière copie locale des credentials Lyra/SystemPay prod. Alex a flairé le danger et m'a arrêté avant tout `rm`. Aucune action destructive prise — `.env.host` byte-identique au backup.

Check ajouté : AVANT de classer "MORT" un secret bancaire/paiement/clé maître : (1) vérifier le rôle de COFFRE (archive éditorial multi-VPS) en plus du runtime, (2) lire les `deploy.yaml`/scripts pour identifier le VPS qui sert réellement le service, (3) sur tout secret SYSTEMPAY_*/STRIPE_*/VADS_*/LYRA_*/OVH_*/POWENS_* : ne JAMAIS purger sans déplacement préalable vers /home/ubuntu/secrets-backups/credentials/ (perms 600). Default = paranoid pour les clés bancaires.

Cause racine : Classifieur basé sur grep littéral des noms de variables (`\bVAR_NAME\b`). Aveugle aux usages dynamiques : déploiements qui sourcent et renomment (PALIMEX_X → X), templates qui remplacent, scripts qui exportent vers VPS distant. Aveugle aussi à la valeur d'archive : un secret peut être "dead code" et pourtant essentiel à conserver.

AtlasMineurConvention
18 mai 2026

Erreur : Audit secrets : conclu à tort que `/home/ubuntu/alexandre-carette-hub/` était un clone hardlinké de synedre-os/ parce que `stat -c %i` renvoyait les mêmes inodes pour les fichiers internes. En réalité c'est un symlink de transition post-rename hub→synedre-os (filet J+7 prévu dans memory project_rename_hub_to_synedre_os). Un `ls -ld` aurait montré immédiatement le `lrwxrwxrwx … → synedre-os`.

Check ajouté : Avant tout raisonnement sur identité d'un répertoire, faire d'abord `ls -ld <path>` ou `readlink -f <path>`. `stat` sur un path symlinké retourne par défaut la cible — piège pour comparer 2 emplacements supposés distincts.

Cause racine : Hypothèse implicite : un nom de répertoire différent = un répertoire physiquement distinct. Faux sur les rename post-migration où les symlinks de compat sont posés en filet J+N.

AtlasModéréConvention
18 mai 2026

Erreur : Audit secrets : `.env.shared` à /home/ubuntu/ (hors-repo) loupé au premier scan car j'ai limité `find` à synedre-os/ et brain/. Or il est référencé en premier dans docker-compose.yml ligne 61 (env_file) et fournit 6 secrets critiques (ANTHROPIC_API_KEY, RESEND_API_KEY, MASTER_WEBHOOK_SECRET, etc.). Détecté en croisant les `env_file:` du compose juste avant la phase d'action — heureusement avant tout `mv`.

Check ajouté : Tout audit env/secrets futur : (1) scanner /home/ubuntu/ ET /etc/ en plus du repo, (2) croiser systématiquement avec les `env_file:` de docker-compose*.yml et les `EnvironmentFile=` des .service systemd AVANT de conclure la liste. Si une variable du runtime n'est dans aucun fichier scanné → il manque un fichier source.

Cause racine : Implicite « tous les secrets vivent sous le repo ». Faux : convention historique du repo place certains secrets hors-repo (.env.shared) pour réduire le risque de leak git accidentel et pour partager entre projets (mentionné dans PORTABILITE.md).

AtlasMajeurConvention
18 mai 2026

Erreur : Mojibake UTF-8 récidivant sur la stack cli-tmux : 4 commits successifs (5e1bc594, a4acdacd, d29891e7, 4498dccd) pour traquer les caractères cassés. Forcer UTF-8 à UN seul endroit ne suffit pas — il faut couvrir les 3 frontières simultanément : (1) env système au lancement subprocess/systemd (LANG=C.UTF-8 + LC_ALL=C.UTF-8), (2) tmux session interne (set -g default-terminal + status-utf8 on), (3) décodage côté navigateur (new TextDecoder('utf-8') sur xterm.js, jamais d'implicit ASCII). Bonus : addon Unicode11 + font sans ligatures pour le rendu propre des caractères larges.

Check ajouté : Avant tout pipe terminal→web : checklist 3 niveaux (env / tmux / TextDecoder) AVANT de pousser. Si un seul niveau pose problème, les autres masquent ou amplifient.

Cause racine : Patcher un seul niveau (ex: juste l'env, ou juste xterm.js) crée l'illusion d'un fix tant que les caractères testés sont ASCII — les accents ne réapparaissent qu'au prochain `é` saisi en preprod.

AtlasModéréConvention
18 mai 2026

Erreur : Estimator LLM oubliait le coût de lecture des fichiers de fondations (CLAUDE.md, doctrine, brain/permanent) — sous-estime systématique des chantiers à fondations lourdes. Cicatrice #665 : ajout d'un facteur dédié + champ foundation_reading_tokens persisté.

Check ajouté : Toute estimation doit comptabiliser séparément (a) tokens skeleton/contexte de tâche et (b) tokens de fondations lues à l'ouverture de session. Les deux ne scalent pas pareil.

Cause racine : Le contexte d'ouverture (CLAUDE.md + memory + brain) est constant par session mais variable selon le scope — l'estimateur le mélangeait avec les tokens travail effectif, écrasant la vérité côté chantiers tenant-multi.

AtlasMajeurConvention
17 mai 2026

Erreur : Chantier standardize-deploy-pattern clôturé en 1 session (8 travaux) : pattern build-local-upload-tar généralisé via dispatcher YAML unique + 7 YAMLs tenants migrés + wrapper ./deploy simplifié + doc CLAUDE.md+INFRA.md+DEPLOY_YAML_SCHEMA.md + pivot extendPages sur store-locator (correction de plugin Nitro cassé par H3 v1.15).

Check ajouté : 1) Avant tout chantier multi-tâches, faire un pré-alignement explicite avec le fondateur sur les axes structurants (DECISIONS LOCKED-IN avant code). 2) Avant tout debug Nitro/middleware URL-rewrite, grep les commentaires des modules adjacents (i18n-routes.ts) : root cause souvent déjà documenté. 3) Avant migration scripts deploy → YAML, faire grep -E par tenant des var hardcodées pour cataloguer exhaustivement (sinon migration incomplète).

Cause racine : Alignement explicite des 4 axes du schéma YAML AVANT codage (Q1-Q4) a évité 3-4 itérations de refacto. Réutilisation du précédent i18n-routes.ts pour identifier root cause locator-rewrite sans deployer. Capture de tous les paramètres tenant par cataloguage shell-grep AVANT écriture des YAMLs. Auto-snapshot hook absorbe les commits manqués sans bloquer.

AtlasModéréConvention
17 mai 2026

Erreur : Chantier standardize-deploy-pattern — focus livré 1 session : 3 tenants Nuxt (codemyshop, codemyshop-demo, alexandrecarette) migrés pattern-A (git pull + build remote) → pattern-B (build local mothership + upload tar pigz + PM2 reload graceful). Lib _deploy_lib.sh factorisée. 4 travaux clôturés, 2 deploys prod successifs HTTP 200, smoke 9/9 cumulé.

Check ajouté : Pour migrer un script deploy-X vers pattern-B : (1) décalque deploy-codemyshop-demo.sh comme template canonique, (2) varier UNIQUEMENT 5-7 vars (LOCAL_CLIENT, REMOTE_DIR, PM2_APP, TAR, DOMAIN, tenant flag, banner), (3) source _deploy_lib.sh et appeler dans l'ordre deploy_build_nuxt → deploy_pack → deploy_upload → deploy_remote_pm2_reload → seed_i18n → deploy_health_check_loop, (4) AUDIT obligatoire des appelants ./ship pour propager --all (cf cicatrice #656), (5) tester ./ship <tenant> --all + smoke avant clôture. Pattern documenté CLAUDE.md §Pattern B.

Cause racine : Décalque strict de deploy-codemyshop-demo.sh (premier script pattern-B en place) pour les 2 suivants — seules 5-7 vars varient (LOCAL_CLIENT, REMOTE_DIR, PM2_APP, TAR, DOMAIN, tenant flag seed, banner). Zéro adaptation gratuite. Les helpers communs (build, pack, upload, remote_pm2_reload, health_check_loop) sont dans _deploy_lib.sh, garantissant phases + breakdown + rollback .output_old identiques. Build local exploite cache .nuxt chaud mothership (CPU 12 cores) vs VPS 2-4 cores — 3-5× plus rapide, traffic réseau /10.

AtlasModéréConvention
17 mai 2026

Erreur : Le wrapper ./ship (lignes 108 + 116) appelait deploy-codemyshop.sh sans --all, contrairement aux 3 autres tenants (synedre/alexandrecarette/corbie qui ont bien --all). Quand deploy-codemyshop.sh a basculé pattern-B (commit 250b51ba travail #123), il a hérité du guard deploy_require_all présent dans _deploy_lib.sh — l'appelant ./ship n'a pas été mis à jour en miroir. Résultat : ship codemyshop sort en exit 1 sans rien déployer. ## Post-mortem (daily-summary) Cas-limite : le bug n'apparaît qu'en bout de chaîne (wrapper → subscript → helper guard). Tester `./ship` directement, pas seulement `deploy-<tenant>.sh`.

Check ajouté : Avant de merger un script qui ajoute deploy_require_all : grep -rn 'deploy-<tenant>.sh' . | grep -v -- '--all' → la liste DOIT être vide (sinon callers à mettre à jour)

Cause racine : Quand un script deploy-* ajoute deploy_require_all (introduit pattern-B), il faut auditer TOUS les appelants (./ship, crons, scripts/scheduler) et leur ajouter --all. La convention 'tous les deploy exigent --all' n'a pas été propagée au wrapper ship pour le cas codemyshop.

AtlasModéréConvention
17 mai 2026

Erreur : Décision archi cicatrice + victoire : option A (colonne kind) > option B (table séparée)

Check ajouté : Avant d'instancier une table parallèle pour un concept 'jumeau', auditer le ratio de champs structurellement équivalents. Si > 80%, préférer un discriminateur (colonne kind/type) dans la table existante.

Cause racine : 95% des champs cicatrice/victoire sémantiquement équivalents. Stocker dans même table évite duplication pipeline embedding + module Nuxt + entity Python.

AtlasMineurmeasurement
16 mai 2026

Erreur : Phase 2b runtime-base-extract — VICTOIRE mesurée : refacto drizzle-pg schema-agnostique + extraction vers runtime-base/ → bundle mothership 96.8→75.7 MB (-22%), gzip 27.2→17.5 MB (-36%). Build time inchangé (199→211s) — le gain build viendra en Phase 3 (bascule extends mothership de codemyshop/core vers codemyshop/runtime-base).

Check ajouté : Pattern à reproduire pour gain bundle : tout fichier qui hardcode N imports de schémas/modules métier doit passer par un assembler (export const fooSchemas = {...}). Permet tree-shaking + extraction propre.

Cause racine : drizzle-pg hardcodait 30+ imports schémas e-commerce → empêchait tree-shaking Rollup côté mothership. Extraction des schémas dans core/_assemblers/db-overlay.ts + drizzle-pg consommant uniquement les 4 overlays (coreSchemas+enterpriseSchemas+internalSchemas+moduleRegistrySchema) = Rollup tree-shake correctement les schémas non utilisés runtime.

AtlasMajeurwrong_assumption
16 mai 2026

Erreur : Phase 2a runtime-base-extract : ma mental model du Nuxt layers extends était fausse — l'alias ~/ ne fait PAS de fallback sur le srcDir du layer parent. ~/server/utils/foo côté core/ cherche dans codemyshop/core/srcDir/server/utils/foo.ts UNIQUEMENT, jamais dans runtime-base/. Conséquence : 30+ imports cassés après git mv, plusieurs retry deploy nécessaires.

Check ajouté : Avant tout git mv entre layers Nuxt : (1) tester avec 1 fichier minimal et builder, (2) grep TOUS les chemins relatifs ../* en plus des alias ~/, (3) si extends ne fallback pas → soit bridge re-export soit migrer en package-name. (4) ajouter le nouveau dir dans le TAR_FILES du script deploy.

Cause racine : Mauvaise mental model de Nuxt 4 layers. La doc dit clairement : "If you want to import something from a layer in another layer, you'll need to do it through the layer name (in package.json) or use relative imports." Pas testé avant le git mv.

AtlasModéréDonnées
15 mai 2026

Erreur : session-replay/snapshots fetch echoue avec 400 Bad Request sur sessions > ~5min (PostHog blob_v2 chunks). PostHog API renvoie validation_error 'Cannot request more than 20 blob keys at once' quand le range start_blob_key..end_blob_key > 20. Code session-replay-snapshots.ts faisait un unique fetch sur la plage min..max sans batching. Decouvert 2026-05-15 sur recording Hamid Lghloussi (zioital777@gmail.com, palimex-v2, 35min session = 141 keys).

Check ajouté : Batcher la plage en chunks de 20 keys, fetch parallele via Promise.all, concat jsonl dans l ordre. Commit afd775a1.

Cause racine : Implementation initiale supposait que PostHog accepte des plages arbitraires. Aucun test sur sessions longues (les premieres validations ne depassaient pas 5 min).

AtlasMajeurDonnées
15 mai 2026

Erreur : Automate gsc-404 ingestion (source_kind='gsc-404' dans ps_ac_redirect) cree des redirects aberrants sans valider si le source_path est deja un slug CMS/categorie actif. Exemples decouverts 2026-05-15 sur palimex prod : /livraison-gratuite -> /contact, /drive-collect -> /grossiste/, /nos-cgv -> /cgv (cible 404 elle-meme), /modes-de-paiement -> /contact. Ces 4 paths sont les slugs reels de ps_cms.link_rewrite (id_cms 1,6,3,5) - l'ingestion les a "repare" en redirigeant n'importe ou. Resultat : pages CMS legitimes inaccessibles, footer Informations casse, traffic SEO perdu. Volume actuel : 479 redirects gsc-404 sur la base palimex_v2 - tous a auditer.

Check ajouté : Patch automate ingestion gsc-404 : avant INSERT INTO ps_ac_redirect, faire LEFT JOIN ps_cms_lang/ps_category_lang sur source_path pour SKIP si match. Backlog P1 audit : DELETE FROM ps_ac_redirect WHERE source_kind='gsc-404' AND source_path IN (SELECT '/' || link_rewrite FROM ps_cms_lang UNION SELECT '/' || link_rewrite FROM ps_category_lang WHERE active=1). Cache memoire 5min dans middleware/02-legacy-redirects.ts donc bump CACHE_TTL_MS ou trigger refresh manuel apres DELETE.

Cause racine : Script GSC ingestion (probablement ac_seo_watch_post_migration.py) consomme une liste 404 GSC et propose une redirection auto, sans verifier que la "404 GSC" n'est pas en fait une page legitime cassee temporairement (cache, deploy intermediaire). L'auto-fix devient un auto-saccage.

AtlasMajeurdebt_code
15 mai 2026

Erreur : Bug template core/pages/[...path].vue (Nuxt catch-all) : <CategoryPage v-if="hasPath" /> est rendu pour TOUT path non-vide, y compris les single-segment slugs CMS comme /mentions-legales, /livraison-gratuite, /nos-cgv. La branche CmsPage (v-else) ne se declenche que pour le root (/). Resultat : tous les CMS pages racine d'un tenant 404 "Categorie introuvable" en SSR alors meme que le script-level cmsPageData est rempli. Decouvert 2026-05-15 sur palimex prod (5 pages Informations footer cassees).

Check ajouté : Fix template : reordonner les branches pour prioriser CmsPage quand cmsPage est truthy meme si hasPath=true. Pattern : <CmsPage v-if="cmsPage" /> <CategoryPage v-else-if="hasPath" />. Workaround temporaire : pointer le footer vers /page/{id_cms} numerique (route core/pages/page/[id].vue qui marche). A appliquer sur core/ + ship a tous tenants. FIX commit 91b69e09 (2026-05-15) : template reordonné — <CmsPage v-if="cmsPage"> puis <CategoryPage v-else-if="hasPath">.

Cause racine : Refacto URL flat 2026-04-25 a deplace la logique CMS-fallback dans la branche v-else (mode "root") sans realiser que les CMS racine ont aussi hasPath=true. Pas d'integration test couvrant render single-segment CMS slug sur catch-all.

AtlasModérédebt_archi
15 mai 2026

Erreur : Drive 2-client_id dans palimex_v2_postgres.ps_ac_footer : 21 rows 'palimex' (anciennes, encore en place + URL preprod cassees /catalogue/...) + 18 rows 'palimex-v2' (live, lues par /api/footer en runtime). Cicatrice decouverte lors audit footer Nos Gammes le 2026-05-15 : j'ai d'abord patche les 13 rows 'palimex' croyant les vraies, sans effet en prod (l'API consultait 'palimex-v2'). Revert puis fix sur les 18 rows live. Violation feedback_tenant_naming_1codename : 1 tenant = 1 codename partout. Le set 'palimex' aurait du etre DELETE post-bascule v2 (2026-05-12).

Check ajouté : Avant tout UPDATE/INSERT cible par client_id sur un tenant, SELECT client_id, COUNT(*) FROM <table> GROUP BY client_id pour identifier les sets obsoletes. Si 2+ codenames pour le meme tenant, DROP/DELETE le legacy AVANT le fix. Backlog P1 : nettoyer toutes les tables ps_ac_* du tenant palimex_v2_postgres ou client_id IN ('palimex','palimex-v2') coexistent.

Cause racine : Bascule preprod -> prod Palimex v2 le 2026-05-12 sans cleanup des seeds 'palimex' creees avant decision du codename 'palimex-v2'. Aucun audit cross-codename declenche post-bascule.

AtlasMineurConvention
15 mai 2026

Erreur : Récidive 2x le 2026-05-15 (apres cicatrice 638 chunk-load) : bugs Vue 3 internes (e.suspense.unmount, "Cannot destructure property bum", reading suspense/bum) + ResizeObserver loop atterrissent dans cs_posthog_errors et polluent /hub/errors malgre leur caractere benin (framework lifecycle teardown race + warning W3C standard). Aucun hook Nuxt equivalent a chunk-reload.client.ts pour ces patterns - la seule defense est un filtre d'ingestion avant INSERT. Lecon : error-tracker doit traiter le bruit framework/browser comme une 1re classe (different du bruit deploy-timing gere par chunk-reload).

Check ajouté : Filtre ingestion etendu dans worker syncSessionErrors : motifs e.suspense.unmount / suspense.unmount / reading bum / reading suspense / ResizeObserver loop. Compteur skippedHandled logge. Si occurrences explosent -> re-evaluer (vrai bug ou nouveau pattern a filtrer).

Cause racine : PostHog (et tout error tracker) capture window.onerror globalement, sans distinguer bug applicatif de framework noise - la responsabilite du filtre repose 100% sur le worker ingestion cote backend, pas sur le SDK navigateur.

AtlasMajeursilent_err
15 mai 2026

Erreur : Email order_payment_pending rendu avec "Montant à régler : " vide → client ignorait combien virer. sendPaymentPendingEmail n'injectait pas {total_paid} ni {history_url} alors que le template DB les attendait. Audit déclenché par récidive HT/TTC (suite c7e782da).

Check ajouté : Audit Explore sur TOUS les senders email à chaque ajout de placeholder DB : grep template content pour {var} et vérifier que le sender injecte tous les vars du template, sinon rendu vide silencieux.

Cause racine : Découplage template DB / sender code : ajout placeholder dans ps_ac_email_template_lang sans audit des consommateurs. Aucun garde-fou type "render failed if missing var".

AtlasModérésilent_err
15 mai 2026

Erreur : PostHog s'attache à window.onerror AVANT que le hook Nuxt chunk-reload.client.ts ne catch les "Importing a module script failed" → faux positifs dans cs_posthog_errors post-deploy (visiteur avec HTML cache + chunk hash changé). chunk-reload reload silencieusement mais l'event est déjà parti.

Check ajouté : Worker syncSessionErrors filtre 4 patterns chunk-load AVANT INSERT cs_posthog_errors. Compteur skippedHandled loggé pour détecter si chunk-reload casse (explosion du nombre = alerte).

Cause racine : Ordre de listener : PostHog SDK init avant plugins Nuxt → window.onerror PostHog gagne. Pas une régression mais un pattern d'architecture à connaître pour tout futur error tracker.

AtlasModéréConvention
15 mai 2026

Erreur : PDFKit gotchas découverts sur quote-pdf.ts (Q-31, devis Bilal 28 produits) : (1) doc.text(name, { width, ellipsis: true }) n'honore pas ellipsis sur fontSize 8 → texte wrap sur 2 lignes mais y += 12 fixe → chevauchements. (2) Colonnes mal calibrées : colSub 480 + width 70 = 550 > marge 545 → PDFKit ajoute des pages fantômes (devis 28 items sur 6 pages au lieu de 2).

Check ajouté : Mesurer doc.heightOfString(text, { width: colW }) AVANT chaque row et incrémenter y de max(rowHeight, measured + padding). Valider que colStart + colWidth <= pageWidth - margin pour CHAQUE colonne, sinon pages fantômes.

Cause racine : PDFKit ellipsis non fiable sur petites fontSizes + math layout naïve (y += constante) qui ignore le rendu réel. Overflow horizontal silencieux (pas d'exception, juste pages vides injectées).

AtlasMajeurConvention
15 mai 2026

Erreur : Récidive 2× le 2026-05-15 : email B2B Palimex affichait TTC sous le label "Total HT produits" (c7e782da) puis "Total TTC" sous le tableau items devis (9f2d8823). Cause : confusion suffix PS `_wt` = "with tax" = TTC vs sans suffix = HT. orders-db.ts:143 prenait total_products_wt en priorité alors que totalProducts est labellé "HT" partout (mon-compte, hub/orders, invoice-pdf, email).

Check ajouté : Audit Explore obligatoire avant tout sender email B2B grossiste : vérifier que les champs DB injectés correspondent au label affiché (HT vs TTC). Pour Palimex tout est HT par défaut, jamais de "Total TTC" visible client.

Cause racine : Convention PrestaShop mal interprétée : `_wt` suffix = TTC, sans suffix = HT — inversion silencieuse côté code orders-db.ts ET côté template email/PDF.

AtlasModéréConvention
11 mai 2026

Erreur : i18n override tenant qui duplique la traduction OSS base : sur Palimex, product.add_to_cart="Acheter" était overridé alors que la base OSS dit déjà "Acheter". Override invisible jusqu'à audit i18n. Pattern récurrent : chaque tenant a son fichier i18n, facile d'overrider sans vérifier si la base traduit déjà identique.

Check ajouté : Avant d'ajouter un override i18n dans tenants/<tenant>/i18n/<lang>.json, grep la clé dans la base community : `rg "<key>" community/i18n/ core/i18n/`. Si la valeur est identique, NE PAS ajouter l'override. Future audit-i18n-keys.py devrait détecter ces no-op overrides.

Cause racine : Convention manquante sur le fork i18n tenant : aucun garde-fou contre le « j'override par habitude ». Le tenant pense qu'il doit redéclarer toutes ses strings, alors qu'il n'override que les différences vraies.

AtlasModéréSécurité
11 mai 2026

Erreur : OSS-leak récurrent : vocabulaire interne (drill, cicatrice, Place des Armes…) trouvé dans core/ post-ship public. Solution réflexe = étendre le scrubber tier-7 (sync-codemyshop-oss.sh) avec une nouvelle règle sed. Mais cumul de tiers scrubber masque la dette réelle : 885 fichiers core/ leakent encore AC-specific, audit-oss-readiness.py compte 660 vaisseau_mere_ac + 212 imports privés (backlog #289 P1). Doubler la couverture scrubber = travail jeté quand on droppe le scrubber.

Check ajouté : Décision tree avant fix d'un leak OSS : (1) si vocab apparaît dans <10 fichiers source = cleanup à la source, jamais scrubber rule. (2) si >10 = scrubber acceptable mais OBLIGATOIREMENT capté en backlog cleanup. (3) audit-oss-readiness.py doit lister la dette avant chaque ship. Voir chantier oss-archi-tenants-mothership Phase 6.1 + backlog #289.

Cause racine : Le scrubber est un pansement, pas une cible : à long terme la doctrine = sync rsync whitelist pur sans transform (chantier oss-archi-tenants-mothership). Chaque tier scrubber ajouté repousse cette cible.

AtlasCritiqueSécurité
10 mai 2026

Erreur : Leak massif OSS public via bootstrap aveugle : codemyshop/codemyshop a publié documentation/ (86 fichiers internes : VPS_REFERENTIEL, CORBIE_*, CONSTITUTION_SYNEDRE, INVENTIONS, PRODUCT_STRATEGY, legal/CHARTE_FACTURATION, CONTROLE_FISCAL_PLAYBOOK) + scripts/ (rungis/palimex enrichments) + README privé Alexandre Carette Hub. 5 min exposition publique avant détection. Repo deleted en urgence HTTP 204. Causes : (1) bootstrap-public-fresh.sh en mode blacklist cp -r aveugle ; (2) scrubber ne couvrait pas vaisseau_mere_ac (134 fichiers) ni lexique interne drill/cicatrice/synedre/atlas/codename (70+ fichiers core/). Commits fix 2000a4fa + d47ec5af.

Check ajouté : Doctrine fermée : OSS publish = whitelist NOMINATIVE obligatoire (jamais blacklist tout-sauf-X). 4 garde-fous automatisés : pre-commit anti-leak, ship gate ABORT, whitelist oss-publish-whitelist.txt, post-push verifier re-clone+grep. Cf memory/feedback_oss_publish_whitelist_only.md.

Cause racine : Mode mental défensif (lister exclusions) au lieu d offensif (lister inclusions). Sous-estimation périmètre privé — supposé que internal+enterprise exclus suffisaient, oubliant documentation/scripts/README/ansible/clients aussi business interne.

AtlasModéréConvention
10 mai 2026

Erreur : tier-resolver.ts utilisait FROM cs_client_vps + cs_marketplace_tenant (tables qui n'existent PAS en DB privée live — vraies tables = ps_ac_client_vps + ps_ac_marketplace_tenant legacy). Code aurait pété en runtime. Doctrine clarifiée : 232 tables ps_ac_* legacy non renommées côté privé, scrubber tier-5 réécrit ps_ac_*→cs_* au sync OSS. Seules NOUVELLES tables (>= 2026-05-10) naissent en cs_*. Commit fix a8c5f07e.

Check ajouté : Avant tout SELECT/INSERT/UPDATE sur table custom : vérifier nom RÉEL en DB live via information_schema, pas appliquer la doctrine de naming aveuglément. Scrubber gère rewrite OSS, code privé reste sur noms réels.

Cause racine : Doctrine cs_* prefix appliquée à des tables existantes 2024 (client_vps, marketplace_tenant) sans vérifier la DB live. Mémoire feedback_naming_cs_prefix.md mentionnait la dichotomie mais lecture trop superficielle.

AtlasMajeurConvention
10 mai 2026

Erreur : gh CLI : "gh run watch --exit-status" renvoie exit 1 même quand le run conclut "success" (bug reproductible certaines versions gh). Le wrapper ship-oss reportait FAILED alors que le Docker workflow v0.2.6 avait publié image + SBOM cyclonedx en 3m14s. Faux négatif silencieux.

Check ajouté : Drop --exit-status, watch en non-strict, puis query autoritative gh run view $RUN_ID --json conclusion --jq .conclusion. SHIP COMPLETE imprimé uniquement si l'API retourne conclusion=="success". Bonus : echo \033 → printf %b%s%b sinon escape codes printed literal.

Cause racine : Confiance dans l'exit code d'une CLI tierce (gh) sans vérifier l'état réel via l'API. Quand un outil expose une API JSON autoritative, c'est elle la source de vérité, pas le exit code.

AtlasModéréConvention
10 mai 2026

Erreur : ship-oss wrapper supposait qu'un push avait toujours eu lieu après le sync. Quand sync est no-op (Phase 6 skippée car aucun commit sur core/), le wrapper passait 25s à chercher un workflow run pour un tag inexistant et concluait "Could not find a workflow run". Le no-op est une valeur de retour légitime, pas un état d'erreur.

Check ajouté : gh api repos/codemyshop/codemyshop/git/refs/tags/<version> AVANT de watcher : 404 = no-op exit 0 avec message clair, 200 = continuer. Présumer side-effect après commande clean = piège récurrent.

Cause racine : Le sync script exit cleanly avec "✓ no changes — sync is a no-op" et le wrapper ne lisait pas ce signal. Toute commande qui peut être no-op exige une vérification explicite côté caller avant d'attendre les artefacts.

AtlasModéréConvention
10 mai 2026

Erreur : automation/oss-sync/translations.cache.json (5444 entries SHA256→EN) est le contrat de reproductibilité OSS. Gitignoré par réflexe = chaque ship repart d'un cache à 15 entries et refait ~20 min de claude -p translate FR→EN pour rien. Le cache committé doit être traité comme du code partagé, pas comme un artefact local.

Check ajouté : Cache committé après le premier --ship v0.2.3. À ne JAMAIS gitignore. Vérifier git status après chaque ship que le delta cache est commité.

Cause racine : Réflexe "fichier généré = gitignore" appliqué à un cache qui matérialise du travail LLM payant non-déterministe (claude -p). Idem futur : embeddings, builds reproductibles, lockfiles d'outils. Distinguer "généré déterministe à partir des sources" (gitignore OK) de "généré à coût LLM/réseau" (commit obligatoire).

AtlasMajeurConvention
10 mai 2026

Erreur : Scrubber OSS AUTHOR_REWRITE était placé en post-tier-5, donc tier-2 avait déjà rewriten le domain (alexandrecarette.fr → codemyshop.com) avant que le grep -F ne cherche AUTHOR_REWRITE_FROM. Résultat : silent no-op pendant des mois — chaque fichier OSS gardait Alexandre Carette en @author + Propriétaire et Confidentiel en @license.

Check ajouté : Refactor en tier-0 (avant tier-2). Tier-0 catche les 3 patterns header JSDoc originaux : @author, @copyright YYYY Alexandre Carette, @license Propriétaire et Confidentiel. 611 fichiers rewritten au dry-run.

Cause racine : Ordre des phases scrubber non-pensé : les rewrites séquentiels invalident les patterns littéraux quand un sous-élément (ex: domaine embedded) a déjà été touché par un tier précédent.

AtlasMajeurConvention
10 mai 2026

Erreur : Scrubber OSS tier-4 + phase 3 sanity utilisaient \bpalimex\b — défait par _ (word char regex). 6 fuites palimex_fruits_secs / palimex_v2_postgres / PalimexSectionType / PALIMEX10 passaient le sanity check vert.

Check ajouté : Tier-4 + sanity regex refactorés en substring match (no boundary), WORD_REWRITES ordre longest-first load-bearing. Documenté dans automation/oss-sync/README.md cicatrices 2026-05-10.

Cause racine : Word boundary \b traite _ comme word char en POSIX/PCRE. Pour identifiers snake_case, ne jamais utiliser \b — substring + tokens ordonnés.

AtlasModéréConvention
10 mai 2026

Erreur : Scrubber OSS tier-2 DOMAIN_REWRITES avait file_globs limité au code (.ts/.vue/.json/etc.). robots.txt / llms.txt / medium-*.html laissaient fuir alexandrecarette.fr dans le snapshot OSS. Sanity check raté car même filtre.

Check ajouté : file_globs étendu à .html/.txt + nouvelle phase 2c (OSS_REMOVE_PATHS) qui supprime les fichiers AC-marketing-only (medium articles, audio, llms.txt) à chaque sync. Auto-régénérant via rsync --existing.

Cause racine : File-glob inclusion list pensée pour code source — oublie les assets statiques publics (robots, llms, html) qui mentionnent les domaines tenants.

AtlasModéréConvention
07 mai 2026

Erreur : Page /hub/categories/[id] mode Centaure : bouton "Appliquer Résumé + Description" semblait inactif. catRedactionStatus était bien set par applyCentaureResponse (succès ou erreur JSON parse) mais l'élément d'affichage <p v-if="catRedactionStatus"> existait UNIQUEMENT dans le bloc <div v-if="aiMode === 'api'">. Mode Centaure -> aucun feedback visible (silent fail). Aggravé par : LLM laissent souvent des newlines littéraux dans valeurs JSON HTML, JSON.parse échoue côté client sans message visible.

Check ajouté : Ref reactive partagé entre 2 branches v-if exclusives doit avoir un élément d'affichage dans CHAQUE branche, ou être hissé hors des v-if. Reflexe de revue : grep le nom de la ref de status, compter les <p v-if="X"> rendus vs branches qui mutent X. Si 2 mutateurs et 1 seul afficheur = silent fail dans une des branches.

Cause racine : Refactor évolutif : ajout du mode Centaure à côté du mode API existant ; le <p v-if="catRedactionStatus"> est resté hérité dans le bloc API. Les deux modes mutent la même ref mais seul API la rend visible.

AtlasModéréConvention
07 mai 2026

Erreur : Page édition catégorie /hub/categories/[id] affichait /img/c/{id}-{slug}-800.webp (PS native) alors que la liste /hub/categories montrait la cover covergen depuis ps_ac_category_covergen_queue. Deux vues sur la même entité avec stratégies de résolution différentes -> désynchro (cas #260 Grossiste). Récidive série #303/#310/#326/#468.

Check ajouté : BO endpoint [id].get.ts enrichit avec coverUrl/thumbUrl via getLatestDoneCoverForCategory(id) aligné avec listLatestDoneCovers de l index. Page [id].vue init catCoverUrl au load.

Cause racine : Cover legacy (queue covergen) prioritaire sur PS native côté liste, mais détail recalculait depuis le slug. Quand un listing enrichit avec un fallback DB, le détail doit faire la même résolution sinon désynchro.

AtlasModérésilent_err
06 mai 2026

Erreur : INSERT ps_ac_smartproject sans colonne needs (NOT NULL sans default) echoue. bookSlot try/catch best-effort swallow l erreur -> lead/projet jamais crees silencieusement. Detection seulement via grep PM2 logs.

Check ajouté : Verifier les colonnes NOT NULL de la table cible AVANT INSERT (information_schema). Pour les wrappers best-effort silencieux, garantir un log clair cote pm2.

Cause racine : INSERT enrichi avec needs=[] coherent format JSON consomme par pipeline UI. Backfill manuel RDV pris avant fix.

AtlasModérépg_keyword
06 mai 2026

Erreur : Colonnes from et to de ps_specific_price sont mots-cles SQL reserves PG. Code legacy by-category.get.ts utilise backticks MariaDB (sp.\`from\`) ignores en PG. Promos ratees sur certaines requetes.

Check ajouté : Sur PG, quoter avec doubles guillemets. Audit autres colonnes problematiques: check, end, group, order, user, table...

Cause racine : Helper getActiveSpecificPrices (core/server/utils/specific-price.ts) avec quoting PG correct, utilise par cart-db + orders-db + product/[id].

AtlasMajeurdrift_blnd
06 mai 2026

Erreur : 6 tables ps_ac_smart* (smartteam, smartautomation_log, smartautomation_rule, smarttask_template, smartlead_rungis, smartlead_rungis_certification) absentes de palimex_v2_postgres + smoke_v2_postgres. /hub/projects/[id] crashe en 500 sur /tasks et /logs cote tenant.

Check ajouté : ac_audit_drizzle_drift.py compare schema-pg/{entity}.ts <-> PG. Tables absentes du TS = angle mort. A backloger: modeliser ces tables en Drizzle ou ajouter audit diff AC <-> tenants independant de Drizzle.

Cause racine : pg_dump --schema-only --table=... depuis ac_postgres puis psql -f sur les 2 tenants. Migration archivee automation/migrations/applied/2026-05-06-tenant-smartproject-tables.sql.

AtlasModéréunit_price
06 mai 2026

Erreur : Produit Meyva Coco 12x200g affichait 8,95 EUR/K (kilo) sur fiche v2 alors qu Aude veut prix par sachet (1,79 EUR). Legacy PS utilise unit_price_ratio mais ne distingue pas multi-pack.

Check ajouté : Regle d inference DB-first dans deriveUnitPricing (core/server/utils/unity-label.ts): unitsPerPack > 1 -> HT/U; sinon unit_price_ratio + unity -> HT/K ou HT/L; sinon fallback poids.

Cause racine : Helper deriveUnitPricing partage entre by-category, cart-db, product/[id]. Label DB-First, pas de HT/K hardcode en template.

AtlasMineurtenant_db
06 mai 2026

Erreur : ?clientId=palimex sur endpoints /api/catalogue/product/[id] depuis tenant Palimex throw 500: useClientDbById path mysql2 droppe. API depend du host-header pour resoudre le tenant.

Check ajouté : Sur endpoints tenant, omettre ?clientId. ?clientId utile UNIQUEMENT depuis ac-hub pour interroger un tenant distant.

Cause racine : Pas de fix code (comportement attendu). Note documentee pour debug futur.

AtlasMajeurConvention
06 mai 2026

Erreur : Password-reset 500 silencieux + 3 endpoints BO (bi/sales, finance/payments, invoices/monthly) cassés en prod depuis le cutover PG du 30/04. Cause : DATE_ADD(NOW(), INTERVAL ? HOUR) avec placeholder MariaDB non porté par db-pg-adapter — les regex 2b/2c ne matchaient que les littéraux INTERVAL <N> UNIT, pas le placeholder ? pour la quantité. Erreur PG noyée dans un .catch côté handler email donc invisible côté logs (UPDATE plantait avant envoi du mail).

Check ajouté : db-pg-adapter.ts: regex 2c-bis/2c-ter ajoutées pour DATE_(SUB|ADD)(expr, INTERVAL ? UNIT) -> (expr ± ? * INTERVAL '1 unit') ET standalone INTERVAL ? UNIT. + password-reset bascule en NOW() + INTERVAL '1 hour' direct (plus robuste que dépendre de adapter pour validityHours=1).

Cause racine : Trou de couverture du wrapper db-pg-adapter pendant le port chantier #44 : les regex de réécriture INTERVAL n'ont été testées que sur des SQL avec quantité littérale (grep statique). Aucun test couvrant le pattern placeholder INTERVAL ? UNIT pourtant courant (validityHours, retentionDays, lookbackHours bindés depuis runtime config). Effet pernicieux : le SELECT/UPDATE plante côté PG mais le code TS l'avale via try/catch large. Audit du 06/05 révèle 15 endpoints supplémentaires ON DUPLICATE KEY UPDATE non portés + 19 scripts Python pymysql actifs + TO_BASE64/FROM_BASE64 dans ac_publisher_engine — phase 5 éviction MariaDB pas terminée.

AtlasModéréConvention
05 mai 2026

Erreur : JSDoc cassé par */ dans doc-block — build esbuild échoue avec "Expected ;". Cicatrice 2026-05-05 sur core/server/api/bo/email-config/smtp.get.ts (process.env.SMTP_*/EMAIL_FROM dans /** */ ferme le commentaire prématurément). Récidive de feedback_jsdoc_cron_notation 2026-05-03.

Check ajouté : Pre-commit hook ne scan pas les doc-blocks pour */ — détection au build seulement. Reformuler en listing explicite (« process.env (SMTP_HOST, SMTP_PORT, EMAIL_FROM) ») au lieu de glob path-style.

Cause racine : Apostrophe glob "*/" dans un commentaire JSDoc multi-ligne ferme le bloc avant la fin attendue. Ni TS ni eslint ne signalent — seul esbuild remonte au transform-time.

AtlasModéréConvention
05 mai 2026

Erreur : SSR mismatch sur /hub/** — sidebar tronquée pré-hydratation. Middleware hub-auth skippe sur SSR (pas de cookie session lisible côté serveur), user.value=null → actualRole tombe sur EMPLOYEE → canAccess(crm|catalogue|orders|...) renvoie false → seules 3 entrées sans v-if (Dashboard, Informations, Playbooks) dans le HTML SSR. Fix routeRules /hub/** ssr:false (commit c31793e5).

Check ajouté : Pattern routeRules ssr:false pour les pages auth-gated sans intérêt SEO (déjà appliqué pour /mon-compte/** côté Palimex). Doctrine : tout BO auth-only → SSR off pour éliminer la fenêtre de mismatch.

Cause racine : Middleware hub-auth a un early return sur import.meta.server. Côté Vue, useState user_auth démarre null sur SSR. Le fallback EMPLOYEE dans actualRole rend l'UI restrictive avant hydratation. Vue ne re-render pas toujours proprement après le mismatch.

AtlasMineurConvention
05 mai 2026

Erreur : Favoris /favoris : bouton « Nouvelle liste » + stats visibles aux non-connectés. Le clic ouvrait la modal, le POST /api/wishlist/lists répondait 401 silently (swallowed côté useWishlist). UX trompeuse : utilisateur saisit un nom, rien ne se passe. Fix v-if=loggedIn sur header CTA + stats (commit 48e7763a).

Check ajouté : Toujours gater côté UI les actions WRITE par l'état d'auth réactif, même si le serveur est correctement gated (requireCustomer). UX > sécurité : un 401 silencieux frustre, un bouton absent guide.

Cause racine : Header rendu indépendamment de l'état loggedIn. Seul le panneau body avait v-if !loggedIn. La modal de création s'ouvrait, l'utilisateur saisissait, puis le POST 401 était attrapé en catch sans toast d'erreur.

AtlasCritiqueSécurité
27 avril 2026

Erreur : sync-modules-tenant.sh lancé sur prod legacy palimex_web pour installer ac_loyalty seul, mais le script déploie TOUS les modules de .tenant-modules absents du tenant. 28 modules (ac_attachmentapi, ac_avatars, ac_base, ac_builder, ac_cartrecovery, ac_categorycovergen, ac_categoryextra, ac_clientconfig, ac_cmscategoryextra, ac_cmsextra, ac_customerextra, ac_employeeextra, ac_faq, ac_footer, ac_header, ac_headlesscontact, ac_homepagesection, ac_hook, ac_instagram, ac_marketplace, ac_megamenu, ac_payment, ac_playbook, ac_prefootersection, ac_productcovergen, ac_productextra, ac_productfood, ac_quoterequest) installés ET 9 dossiers copiés (ac_homepageblock, ac_redirect, ac_routing, ac_smartlead, ac_smartproject, ac_telemetry, ac_theme, ac_translate, ac_wishlistextra). Kill du process déclenché à temps. Rollback complet : 28 uninstall via PS console + 9 dossiers supprimés via SFTP. Site Palimex prod resté HTTP 200 pendant tout l incident.

Check ajouté : Patcher sync-modules-tenant.sh : ajouter flag --only <module> qui restreint le déploiement à un module unique de la whitelist. Sans ce flag, comportement actuel = installe TOUTE la whitelist absente. Sur tenant vierge en ac_*, ne JAMAIS lancer sync-modules-tenant.sh sans --only.

Cause racine : sync-modules-tenant.sh est conçu pour synchroniser des modules ac_* DEJA PRESENTS + installer les nouveaux de la whitelist. Sur un tenant vierge en ac_*, il assume que toute la whitelist doit être déployée d un coup. Pour 1ère install ciblée, il aurait fallu un flag --only ac_loyalty. Le devis Aude portait UNIQUEMENT sur le module fidélité.

AtlasMajeurConvention
26 avril 2026

Erreur : Debug 500 PrestaShop bloqué 1h+ pendant P0 client : body vide reçu, PS_MODE_DEV=true ne suffit pas car le fatal frappe AVANT le handler erreur PS (init bootstrap). Apache servait empty 500 → impossible de voir la cause sans lire le error.log du container.

Check ajouté : Réflexe systématique sur tout 500 PrestaShop : activer display_errors=On dans /usr/local/etc/php/conf.d/zz-debug.ini puis docker restart container AVANT toute autre investigation. Pour SSH+tail backgroundisé : redirect remote file → scp → cat local en commande unique.

Cause racine : PHP display_errors=Off par défaut sur image apache+php prod. PS debug mode n agit qu une fois PrestaShop bootstrap. Aussi : trailing slash absent du form action = 301 redirect = POST data perdu (sendMessage jamais appelé).

AtlasModéréConvention
24 avril 2026

Erreur : padding + radius cards legacy (override thème Palimex) (commit 6afb2124)

Check ajouté : padding + radius cards legacy (override thème Palimex)

AtlasModéréConvention
24 avril 2026

Erreur : tpl hooks PS legacy — markup aligné thèmes Panda / Classic (commit c7ab0f33)

Check ajouté : tpl hooks PS legacy — markup aligné thèmes Panda / Classic

AtlasModéréConvention
24 avril 2026

Erreur : front account.tpl — extends customer/page.tpl explicite (commit 8a065b0f)

Check ajouté : front account.tpl — extends customer/page.tpl explicite

AtlasModéréConvention
23 avril 2026

Erreur : robustesse parser env + seuil sanity abaissé (Phase 2 done) (commit a0cc5192)

Check ajouté : robustesse parser env + seuil sanity abaissé (Phase 2 done)

AtlasModéréConvention
23 avril 2026

Erreur : Nuxt 3.17.5 -> 4.4.2 migration SUCCESS en 15 min. Stratagie : bump package.json + future.compatibilityVersion:4 dans core/nuxt.config.ts. Build tous tenants OK (AC/CMS/PAL/SMK), zero code metier touche. Pas de breaking change ressenti grace au compat mode qui absorbe useAsyncData/Nitro changes.

Check ajouté : Sur futures migrations majeurs Nuxt, tester d'abord le compat mode avant bump package (ici compat mode + bump direct ensemble ont marche).

Cause racine : Nos pages/composants respectent deja les conventions Nuxt modernes (Composition API, useAsyncData, useFetch). Pas d'usage de deprecated APIs. Le compat mode et le bump 4.x coexistent sans friction.

Avis vérifiés

Nos clients parlent de nous

5.0 / 5

33 avis clients

Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son a

Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son accompagnement. Alexandre comprend parfaitement les enjeux et problématiques liés à notre activité et parvient, en réponse, à nous apporter des solutions techniques et fonctionnelles en respectant coûts et délais.

Office

MONOGRAM

Malt

La résolution de mes problèmes à été rapide et efficace, je recommande :)

La résolution de mes problèmes à été rapide et efficace, je recommande :).

Marine

MES-Distribution

Malt

Super

Super

Jl

Kaigan

Malt

Au Top

Au Top. tout simplement

Elite Cbd

Canna Elite Europe Ltd

Malt

Configuration d''un VPS et migration réalisée avec succès, bons conseils, dia

Configuration d'un VPS et migration réalisée avec succès, bons conseils, diagnostique rapide et efficace de nos problèmes. Je recommande.

Lorie

GRIIN outdoor

Malt

Toujours aussi clair et clairvoyant

Toujours aussi clair et clairvoyant... ;) Un plaisir de travailler avec Alexandre

Elite Cbd

Canna Elite Europe Ltd

Malt