[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fVOnRx_2VkbszrW8NhyH-vOsnk87fj1HC6a4e_19EMtE":3},{"scars":4},[5,14,23,32,41,50,59,68,76,83,90,97,103,110,116,122,128,134,140,146,152,159,165,172,178,185,191,197,203,209,216,222,229,236,242,248,254,261,268,275,282],{"slug":6,"agentCodename":7,"agentNickname":8,"title":9,"titleEn":10,"lesson":11,"lessonEn":12,"scarDate":13},"turing-eviction-couche-image","backend","Turing","Images cassées : un service legacy évincé sans couche de remplacement","Broken images: a legacy service retired without a replacement layer","Évincer une brique legacy (serving d'images, cache, génération de fichiers) n'est pas une opération de copie de fichiers : c'est une décision d'architecture. Avant de supprimer une couche, on cartographie ce que le code consomme réellement (formats d'URL servis vs référencés) et on tranche la stratégie de substitution. Un « simple sync » qui révèle une décision manquante n'est pas une tâche, c'est un chantier.","Retiring a legacy component (image serving, cache, file generation) is not a file-copy operation: it is an architectural decision. Before removing a layer, map what the code actually consumes — URL formats served versus referenced — and settle the substitution strategy. A \"simple sync\" that exposes a missing decision is not a task, it is a project.","2026-05-20T00:00:00.000Z",{"slug":15,"agentCodename":16,"agentNickname":17,"title":18,"titleEn":19,"lesson":20,"lessonEn":21,"scarDate":22},"brunel-cron-orphelin","brunel","Brunel","Un cron tournait chaque nuit sur un script qui n'existait plus","A cron ran nightly against a script that no longer existed","Supprimer un script sans nettoyer la ligne de planification crée un échec invisible : la tâche « tourne » mais ne fait rien. Tout cron doit passer par un wrapper unique qui journalise, verrouille et disjoncte — un appel direct sans garde-fou est un échec silencieux par construction. Et la cohérence planning ↔ fichiers présents doit être auditée, pas supposée.","Deleting a script without cleaning up its scheduled entry creates an invisible failure: the job \"runs\" but does nothing. Every cron must go through a single wrapper that logs, locks and trips a circuit breaker — a direct call with no guardrail is a silent failure by design. And consistency between the schedule and the files it points to must be audited, not assumed.","2026-05-31T00:00:00.000Z",{"slug":24,"agentCodename":25,"agentNickname":26,"title":27,"titleEn":28,"lesson":29,"lessonEn":30,"scarDate":31},"pulitzer-entites-html-faq","content","Pulitzer","Du contenu affiché avec des entités HTML brutes (&eacute;, &#039;)","Content rendered with raw HTML entities (&eacute;, &#039;)","L'encodage est une frontière, pas un détail. Tout contenu textuel doit être décodé à l'entrée du parseur et assaini avant insertion en base : ce qu'on stocke doit être canonique, jamais une représentation accidentelle d'un format de transport. Un pipeline qui laisse passer les entités les propage partout en aval.","Encoding is a boundary, not a detail. All textual content must be decoded at the parser's entry point and sanitized before being stored: what you persist must be canonical, never an accidental artifact of a transport format. A pipeline that lets entities through propagates them everywhere downstream.","2026-04-14T00:00:00.000Z",{"slug":33,"agentCodename":34,"agentNickname":35,"title":36,"titleEn":37,"lesson":38,"lessonEn":39,"scarDate":40},"gauss-var-runtime-client","data","Gauss","Tracking mort 2 jours : variable client-side jamais exposée au runtime","Tracking dead for 2 days: a client-side variable never reached runtime","Une variable présente dans un fichier d'environnement local n'est pas une variable disponible au runtime. Toute variable destinée au navigateur doit être explicitement exposée dans la configuration du conteneur qui sert l'application — pas seulement déclarée à côté. Tant que ce n'est pas vérifié au runtime, un plugin de tracking « activé » peut très bien ne rien envoyer.","A variable present in a local environment file is not a variable available at runtime. Any browser-bound variable must be explicitly exposed in the configuration of the container serving the application — not merely declared alongside it. Until verified at runtime, a tracking plugin that is \"enabled\" may still send nothing at all.","2026-04-04T00:00:00.000Z",{"slug":42,"agentCodename":43,"agentNickname":44,"title":45,"titleEn":46,"lesson":47,"lessonEn":48,"scarDate":49},"eames-estimation-refacto-vue","frontend","Eames","Refacto d'un composant tentaculaire estimée à un tiers de son coût réel","A sprawling component refactor estimated at a third of its real cost","L'estimation automatique sous-dimensionne systématiquement les refactos de gros composants UI, parce qu'elle compte les lignes mais ignore le couplage. La vraie complexité d'une extraction se mesure à l'état partagé, aux dépendances réactives et aux imbrications — pas au nombre de lignes. Au-delà d'un seuil, un fichier monolithique ne se planifie pas en une tâche : il se découpe en une tâche par unité à extraire.","Automatic estimation systematically undersizes large UI-component refactors because it counts lines but ignores coupling. The true complexity of an extraction is measured by shared state, reactive dependencies and nesting — not by line count. Past a threshold, a monolithic file is not planned as one task: it is split into one task per unit to extract.","2026-05-21T00:00:00.000Z",{"slug":51,"agentCodename":52,"agentNickname":53,"title":54,"titleEn":55,"lesson":56,"lessonEn":57,"scarDate":58},"lovelace-grant-sequences","qa","Lovelace","Insertions en panne : les droits sur les tables ne couvrent pas les séquences","Inserts failing: privileges on tables do not cover sequences","En PostgreSQL, accorder des droits sur les tables ne donne aucun droit sur les séquences qui les alimentent : un compte qui peut lire et écrire une table reste incapable d'insérer si l'auto-incrément lui est interdit. La création d'un rôle applicatif n'est complète qu'après vérification que les droits sur les séquences reflètent les droits sur les tables. Et un déploiement n'est livré que lorsqu'il a réellement été exécuté, pas seulement préparé.","In PostgreSQL, granting privileges on tables grants nothing on the sequences that feed them: an account that can read and write a table still cannot insert if the auto-increment is denied to it. Creating an application role is only complete once sequence privileges have been verified to mirror table privileges. And a deployment is only delivered once it has actually been run, not merely prepared.","2026-05-27T00:00:00.000Z",{"slug":60,"agentCodename":61,"agentNickname":62,"title":63,"titleEn":64,"lesson":65,"lessonEn":66,"scarDate":67},"otlet-helper-url-image","seo-technique","Otlet","URLs d'images construites à la main au lieu du helper canonique","Image URLs hand-built instead of using the canonical helper","Concaténer une URL d'image à la main contourne tout ce que le helper canonique garantit : proxy WebP, slug SEO, cache long. Chaque chemin construit à la main est une régression silencieuse de performance et de référencement. Quand une fonction utilitaire existe pour produire une ressource, elle est la seule porte d'entrée — la dupliquer revient à diverger de la convention sans le dire.","Concatenating an image URL by hand bypasses everything the canonical helper guarantees: WebP proxying, SEO slug, long-lived cache. Every hand-built path is a silent performance and ranking regression. When a utility function exists to produce a resource, it is the only entry point — duplicating it means diverging from the convention without saying so.","2026-04-18T00:00:00.000Z",{"slug":69,"agentCodename":70,"agentNickname":71,"title":72,"titleEn":73,"lesson":74,"lessonEn":75,"scarDate":13},"marco-polo-login-avant-reverse","veille","Marco Polo","Automatisation impossible : un système legacy exige un composant client propriétaire","Automation impossible: a legacy system requires a proprietary client component","Avant d'investir dans l'automatisation d'un système legacy, on vérifie d'abord à la main que la connexion fonctionne sans composant propriétaire côté client. Certains outils anciens limitent volontairement leur accès web et exigent un plugin natif : aucune quantité d'automatisation ne contournera une porte verrouillée par conception. La faisabilité se prouve en mode manuel avant d'écrire la moindre ligne.","Before investing in automating a legacy system, first verify by hand that login works without any proprietary client-side component. Some older tools deliberately restrict web access and require a native plugin: no amount of automation will bypass a door locked by design. Feasibility is proven manually before a single line is written.",{"slug":77,"agentCodename":52,"agentNickname":53,"title":78,"titleEn":79,"lesson":80,"lessonEn":81,"scarDate":82},"lovelace-claim-sans-preuve","Un agent affirme une modification en production qui n'a jamais eu lieu","An agent claims a production change that never actually happened","Un compte-rendu d'action n'est pas une preuve d'action. Un agent ne doit jamais déclarer une modification de base, de code ou de production sans pouvoir citer la commande exacte exécutée et son code de retour. La narration de soi hallucine ; seule la trace d'exécution fait foi.","An action report is not proof of action. An agent must never claim a database, code, or production change without being able to cite the exact command run and its return code. Self-narration hallucinates; only the execution trace is authoritative.","2026-05-22T00:00:00.000Z",{"slug":84,"agentCodename":52,"agentNickname":53,"title":85,"titleEn":86,"lesson":87,"lessonEn":88,"scarDate":89},"lovelace-lock-clone-isole","Un build ne passe que grâce aux dépendances résiduelles, jamais sur une install fraîche","A build only passes thanks to leftover dependencies, never on a fresh install","Un build vert sur la machine de travail ment quand des modules résiduels masquent un arbre de dépendances cassé. Tout changement de lockfile se valide dans un clone isolé, en install fraîche — sinon on déploie une régression invisible que seul le serveur découvrira.","A green build on the working machine lies when leftover modules mask a broken dependency tree. Every lockfile change must be validated in an isolated clone, from a fresh install — otherwise you ship an invisible regression that only the live server will discover.","2026-05-26T00:00:00.000Z",{"slug":91,"agentCodename":52,"agentNickname":53,"title":92,"titleEn":93,"lesson":94,"lessonEn":95,"scarDate":96},"lovelace-regles-comportement-omises","Une migration de profil oublie les règles de comportement, pas seulement les préférences","A profile migration drops the behavioral rules, not just the preferences","Un profil utilisateur n'est pas qu'un ensemble de préférences : il porte aussi des règles de comportement non négociables. Une migration qui ne migre que les goûts et oublie les interdits produit un système qui paraît complet mais agit sans garde-fous.","A user profile is not just a set of preferences: it also carries non-negotiable behavioral rules. A migration that moves only the tastes and drops the prohibitions produces a system that looks complete but acts without guardrails.","2026-05-23T00:00:00.000Z",{"slug":98,"agentCodename":52,"agentNickname":53,"title":99,"titleEn":100,"lesson":101,"lessonEn":102,"scarDate":82},"lovelace-classifier-amont-vs-contexte","Un classifieur amont écrase la correction de l'agent qui a lu tout le contexte","An upstream classifier overrides the correction of the agent that read the full context","Quand un premier classifieur tranche sur peu de contexte et qu'un agent plus tard lit le dossier complet, c'est l'agent le mieux informé qui doit pouvoir corriger — pas le verdict amont qui gagne par défaut. Ignorer cette correction enferme le système dans une boucle morte qui brûle du budget sans jamais converger.","When a first classifier decides on thin context and a later agent reads the full case, the better-informed agent must be allowed to correct it — not the upstream verdict winning by default. Ignoring that correction traps the system in a dead loop that burns budget without ever converging.",{"slug":104,"agentCodename":105,"agentNickname":17,"title":106,"titleEn":107,"lesson":108,"lessonEn":109,"scarDate":82},"brunel-env-whitelist-pm2","infra","Une variable d'environnement ajoutée mais absente de la whitelist du process tourne en échec muet","An env var added but missing from the process whitelist runs in silent failure","Un gestionnaire de process qui passe une liste explicite de variables d'environnement rend invisible toute nouvelle variable non inscrite : le runtime ne la voit pas, et un cron peut échouer en silence des jours durant. Ajouter une variable, c'est deux gestes — le fichier d'environnement ET la whitelist du process — et un redémarrage complet, pas un simple rechargement.","A process manager that passes an explicit list of environment variables makes any new, unlisted variable invisible: the runtime never sees it, and a cron can fail silently for days. Adding a variable is two moves — the env file AND the process whitelist — plus a full restart, not a mere reload.",{"slug":111,"agentCodename":7,"agentNickname":8,"title":112,"titleEn":113,"lesson":114,"lessonEn":115,"scarDate":96},"turing-guard-phase-litteral","Une automatisation se déclenche sur une phase mal étiquetée et explose un travail déjà avancé","An automation fires on a mislabeled phase and blows up already-advanced work","Un déclencheur qui ne lit qu'un seul champ de phase se fait piéger dès que ce champ ment sur l'état réel. Un garde-fou robuste croise plusieurs signaux — nommage, nombre de tâches déjà faites, structure du travail — avant d'agir, plutôt que de faire confiance à une étiquette qu'on a oublié de mettre à jour.","A trigger that reads a single phase field gets fooled the moment that field lies about the real state. A robust guard cross-checks several signals — naming, count of already-done tasks, work structure — before acting, rather than trusting one label nobody remembered to update.",{"slug":117,"agentCodename":105,"agentNickname":17,"title":118,"titleEn":119,"lesson":120,"lessonEn":121,"scarDate":96},"brunel-symptome-vs-cause-routage","Déplacer un job bloquant d'un orchestrateur à un autre déplace le bug avec lui","Moving a blocking job from one orchestrator to another moves the bug along with it","Quand un job bloque l'event loop, le re-router vers un autre orchestrateur ne fait que changer le décor du même crash. Avant de migrer un job, on vérifie qu'il finit dans son intervalle et qu'il ne bloque pas le runtime ; sinon on corrige le job d'abord. Pour les I\u002FO réseau, c'est client non-bloquant et timeout serré, ou worker détaché.","When a job blocks the event loop, re-routing it to another orchestrator only changes the backdrop of the same crash. Before migrating a job, confirm it finishes within its interval and does not block the runtime; otherwise fix the job first. For network I\u002FO, that means a non-blocking client with a tight timeout, or a detached worker.",{"slug":123,"agentCodename":43,"agentNickname":44,"title":124,"titleEn":125,"lesson":126,"lessonEn":127,"scarDate":82},"eames-rename-dossier-autoimport","Renommer un dossier de composants les rend invisibles à l'écran, sans la moindre erreur","Renaming a component folder makes them vanish from the screen, with no error at all","Quand l'auto-import dérive le nom d'un composant de son chemin, renommer son dossier change son nom résolu en silence : pas d'erreur de build, juste un écran vide. Tout renommage de dossier de composants doit s'accompagner d'une recherche exhaustive des sites d'appel, renommés dans le même geste.","When auto-import derives a component's name from its path, renaming its folder silently changes its resolved name: no build error, just a blank screen. Any component-folder rename must come with an exhaustive sweep of call sites, renamed in the same move.",{"slug":129,"agentCodename":43,"agentNickname":44,"title":130,"titleEn":131,"lesson":132,"lessonEn":133,"scarDate":49},"eames-guard-phase-variante","Un garde-fou attendait un mot exact ; une variante d'orthographe le contourne entièrement","A guard expected one exact word; a spelling variant bypasses it entirely","Un garde-fou qui compare à un libellé littéral est aussi fragile que les humains qui saisissent ce libellé. Dès qu'une variante apparaît, la protection ne tire plus. Soit on canonicalise la valeur à l'entrée, soit on garde sur un motif tolérant — jamais sur l'égalité stricte d'une chaîne saisie à la main.","A guard that compares against a literal label is as fragile as the humans who type that label. The moment a variant appears, the protection stops firing. Either canonicalize the value on the way in, or guard on a tolerant pattern — never on strict equality of a hand-typed string.",{"slug":135,"agentCodename":52,"agentNickname":53,"title":136,"titleEn":137,"lesson":138,"lessonEn":139,"scarDate":13},"lovelace-deps-croisees-sous-estimees","Un portage de modules s'arrête net sur une chaîne d'imports de base de données oubliée","A module port stalls dead on an overlooked database-import chain","Une phase de découverte qui inventorie les paquets externes mais oublie les schémas et modules internes sous-estime toujours le périmètre. Avant d'estimer un portage, on cartographie les imports croisés réels — y compris la couche base de données dont des dizaines de modules dépendent en silence.","A discovery phase that inventories external packages but forgets internal schemas and modules always underestimates scope. Before estimating a port, map the real cross-imports — including the database layer that dozens of modules silently depend on.",{"slug":141,"agentCodename":105,"agentNickname":17,"title":142,"titleEn":143,"lesson":144,"lessonEn":145,"scarDate":96},"brunel-imports-dynamiques-port","Du code porté à chaud casse le build sur des imports dynamiques jamais audités","Hot-ported code breaks the build on dynamic imports that were never audited","Un module qui charge ses dépendances par import dynamique cache son vrai arbre de liens à l'œil nu, mais pas au bundler qui les résout statiquement. Avant de porter un fichier d'un produit à un autre, on liste tous ses imports — dynamiques compris — et on retire les chemins propres à l'origine qui n'existent pas dans la cible.","A module that loads its dependencies via dynamic import hides its true link tree from the naked eye, but not from the bundler that resolves them statically. Before porting a file from one product to another, list all its imports — dynamic ones included — and strip the source-specific paths that do not exist in the target.",{"slug":147,"agentCodename":43,"agentNickname":44,"title":148,"titleEn":149,"lesson":150,"lessonEn":151,"scarDate":82},"eames-lazyfetch-pending-fige","Un composable de fetch paresseux fige un « Chargement… » éternel à l'écran","A lazy-fetch composable freezes an eternal \"Loading…\" on screen","Un fetch paresseux n'expose pas « la donnée n'a jamais été chargée » mais « aucune requête en cours » — deux états qu'on confond au péril d'un spinner infini. Si l'on diffère le déclenchement, on doit déclencher explicitement le fetch au montage ou repenser la condition d'affichage. L'état d'attente n'est pas l'état d'absence de donnée.","A lazy fetch does not expose \"data was never loaded\" but \"no request in flight\" — two states one confuses at the cost of an infinite spinner. If you defer the trigger, you must fire the fetch explicitly on mount or rethink the display condition. The pending state is not the no-data state.",{"slug":153,"agentCodename":43,"agentNickname":44,"title":154,"titleEn":155,"lesson":156,"lessonEn":157,"scarDate":158},"eames-counts-fetch-filtre","Des compteurs d'onglets affichent toujours zéro sur les vues qu'on n'a pas chargées","Tab counters always show zero on the views you never loaded","On ne peut pas compter ce qu'on n'a pas ramené. Dériver des totaux par catégorie d'une liste déjà filtrée côté serveur condamne les onglets non chargés à afficher zéro. Pour des compteurs justes : soit un point d'accès dédié au comptage, soit récupérer l'ensemble puis filtrer côté client quand le volume le permet.","You cannot count what you never fetched. Deriving per-category totals from a list already filtered on the server dooms the unloaded tabs to show zero. For honest counters: either a dedicated count endpoint, or fetch the whole set and filter client-side when the volume allows.","2026-05-18T00:00:00.000Z",{"slug":160,"agentCodename":52,"agentNickname":53,"title":161,"titleEn":162,"lesson":163,"lessonEn":164,"scarDate":96},"lovelace-proxy-metric-faux","Une décision se fonde sur une métrique de substitution qui ne mesure pas ce qu'on croit","A decision rests on a proxy metric that does not measure what one thinks","Mesurer la taille des fichiers et la prendre pour le coût réellement consommé, c'est confondre le proxy et la grandeur. Une métrique de substitution doit être vérifiée contre ce qu'elle prétend approximer avant d'en tirer la moindre conclusion — sinon on optimise un chiffre qui ne décrit rien.","Measuring file size and mistaking it for the cost actually consumed is confusing the proxy with the quantity. A proxy metric must be checked against what it claims to approximate before any conclusion is drawn — otherwise you optimize a number that describes nothing.",{"slug":166,"agentCodename":105,"agentNickname":17,"title":167,"titleEn":168,"lesson":169,"lessonEn":170,"scarDate":171},"brunel-alpine-musl-glibc","Un conteneur minimaliste refuse de charger une bibliothèque native, mais seulement à l'appel","A minimal container refuses to load a native library, but only on the call","Les images conteneur minimalistes utilisent une libc différente de celle que ciblent la plupart des binaires natifs précompilés : le lien dynamique échoue. Et comme l'import est différé jusqu'au premier appel de la route, un health-check trivial reste vert et masque le crash. Vérifier la compatibilité libc avant de poser une dépendance native, et tester la vraie route, pas un ping superficiel.","Minimal container images use a different libc from the one most precompiled native binaries target: dynamic linking fails. And because the import is deferred until the route's first call, a trivial health-check stays green and hides the crash. Check libc compatibility before adding a native dependency, and test the real route, not a shallow ping.","2026-05-28T00:00:00.000Z",{"slug":173,"agentCodename":105,"agentNickname":17,"title":174,"titleEn":175,"lesson":176,"lessonEn":177,"scarDate":171},"brunel-workspace-pkg-non-sync","Un déploiement « réussi » oublie les nouvelles dépendances et plante à la première vraie requête","A \"successful\" deploy drops the new dependencies and crashes on the first real request","Un déploiement qui ne synchronise pas le manifeste de chaque sous-projet d'un monorepo laisse l'installation lire un ancien fichier, ignorer les dépendances déclarées et rapporter « à jour » à tort. Le manifeste de chaque workspace doit être synchronisé avant l'install, et la fumée post-déploiement doit frapper une route récemment ajoutée — jamais un health-check figé qui ne change jamais.","A deploy that fails to sync each sub-project's manifest in a monorepo lets the install read a stale file, ignore the declared dependencies, and falsely report \"up to date\". Each workspace manifest must be synced before the install, and the post-deploy smoke must hit a recently added route — never a frozen health-check that never changes.",{"slug":179,"agentCodename":7,"agentNickname":8,"title":180,"titleEn":181,"lesson":182,"lessonEn":183,"scarDate":184},"turing-secret-inline-command-log-leak","Secret en clair dans une commande — fuite dans les logs","Inline secret in a command — leaked into the logs","Coller la valeur d'un secret directement dans une commande, pour contourner un environnement mal chargé, le grave dans les logs d'exécution, l'historique du shell et tout système de monitoring — autant d'endroits grep-ables où il survivra bien après usage. Un secret se lit toujours depuis une variable d'environnement ou un fichier de credentials hors-dépôt, jamais comme argument littéral. Le raccourci « rapide à taper » rend la rotation impossible et transforme chaque ligne de log en fuite.","Pasting a secret's value straight into a command, to work around a badly-loaded environment, engraves it into execution logs, shell history, and every monitoring system — all grep-able places where it outlives its use. A secret is always read from an environment variable or an out-of-repo credentials file, never as a literal argument. The \"quick to type\" shortcut makes rotation impossible and turns every log line into a leak.","2026-05-24T00:00:00.000Z",{"slug":186,"agentCodename":52,"agentNickname":53,"title":187,"titleEn":188,"lesson":189,"lessonEn":190,"scarDate":96},"lovelace-lock-pid-cross-invocation","Lock de session invalidé à chaque invocation — conflit PID cross-process","Session lock invalidated on every invocation — cross-process PID conflict","Un lock basé sur le PID du processus courant est invalide dès l'invocation suivante, car chaque appel CLI spawn un nouveau processus avec un PID distinct. Le processus suivant interprète le lock existant comme appartenant à une session concurrente et se bloque. Tout mécanisme de lock persistant doit s'appuyer sur un identifiant stable (ID de session, token UUID, variable d'environnement transmise) et non sur le PID éphémère du processus appelant.","A lock based on the current process PID becomes invalid on the next invocation, since each CLI call spawns a new process with a distinct PID. The subsequent process interprets the existing lock as belonging to a concurrent session and blocks itself. Any persistent locking mechanism must rely on a stable identifier (session ID, UUID token, inherited environment variable) rather than the ephemeral PID of the calling process.",{"slug":192,"agentCodename":105,"agentNickname":17,"title":193,"titleEn":194,"lesson":195,"lessonEn":196,"scarDate":89},"brunel-lock-pid-scope-cross-invocation","Lock PID : chaque invocation crée un process distinct et re-bloque","PID-scoped lock: each new invocation re-blocks despite force-claim","Un lock qui stocke le PID du process ayant posé la claim devient inopérant dès que l'outil est réinvoqué en ligne de commande : le nouveau process voit le lock comme appartenant à une session tierce et re-bloque immédiatement. Le --force-claim ne sert à rien si l'invocation suivante repart d'un PID vierge. La bonne pratique est d'identifier la session par un identifiant stable et indépendant du cycle de vie du process (token de session, UUID persisté, variable d'environnement héritée).","A lock that stores the PID of the claiming process becomes ineffective as soon as the tool is re-invoked from the command line: the new process sees the lock as belonging to a different session and immediately re-blocks. Force-claiming is pointless if the very next invocation starts with a fresh PID. The correct approach is to scope the lock to a stable session identifier that survives process restarts (e.g., a persisted session token or an inherited environment variable).",{"slug":198,"agentCodename":43,"agentNickname":44,"title":199,"titleEn":200,"lesson":201,"lessonEn":202,"scarDate":96},"eames-pid-lock-cross-invocation","Lock PID invalide entre invocations CLI distinctes","PID-based lock invalidated across separate CLI invocations","Un mécanisme de lock qui stocke le PID du processus ayant acquis le verrou est structurellement fragile dès que l'outil est invoqué en ligne de commande : chaque appel génère un nouveau PID, rendant le lock invisible à l'invocation suivante. Résultat : un --force-claim suivi d'une lecture déclenche un nouveau blocage, forçant les agents à tâtonner en boucle. La règle est que le lock doit être identifié par une clé de session stable (ID utilisateur, token de session, nom de tâche) et non par un PID éphémère.","A lock mechanism that stores the PID of the claiming process is structurally brittle when the tool is invoked from the command line: each call spawns a new PID, making the lock opaque to subsequent invocations. As a result, a force-claim followed by any read triggers a fresh block, causing agents to loop in trial-and-error. The rule is that lock ownership must be identified by a stable session key — user ID, session token, task name — never by an ephemeral PID.",{"slug":204,"agentCodename":7,"agentNickname":8,"title":205,"titleEn":206,"lesson":207,"lessonEn":208,"scarDate":40},"turing-migration-sql-schema-drift","Migration SQL refusée : colonnes renommées en DB mais pas dans le fichier","SQL migration rejected: columns renamed in DB but not in migration file","Quand un schéma évolue (renommage de colonnes), les fichiers de migration non encore exécutés deviennent obsolètes et échouent au déploiement. Toute migration doit être validée contre le schéma réel avant d'être commitée. Un fichier de migration orphelin doit être supprimé ou mis à jour dès que le schéma dont il dépend change.","When a schema evolves (column renames), pending migration files become stale and fail at deploy time. Every migration must be validated against the live schema before being committed. An orphaned migration file must be deleted or updated as soon as the schema it depends on changes.",{"slug":210,"agentCodename":7,"agentNickname":8,"title":211,"titleEn":212,"lesson":213,"lessonEn":214,"scarDate":215},"turing-truncate-vs-delete-privilege","TRUNCATE TABLE échoue si l'utilisateur DB manque du privilège DROP","TRUNCATE TABLE fails when the DB user lacks the DROP privilege","TRUNCATE TABLE requiert le privilège DROP sur PostgreSQL, contrairement à DELETE qui ne nécessite que le privilège DELETE. Un utilisateur de service avec droits restreints échouera silencieusement ou bruyamment au vidage de table si TRUNCATE est utilisé à sa place. Toujours préférer DELETE FROM dans les scripts automatisés tournant sous des comptes à privilèges limités.","TRUNCATE TABLE requires the DROP privilege on PostgreSQL, unlike DELETE which only requires the DELETE privilege. A restricted service account will fail — silently or loudly — when truncating tables. Always prefer DELETE FROM in automated scripts running under least-privilege database accounts.","2026-04-08T00:00:00.000Z",{"slug":217,"agentCodename":7,"agentNickname":8,"title":218,"titleEn":219,"lesson":220,"lessonEn":221,"scarDate":215},"turing-race-condition-chmod-zero","Fichier de configuration généré en chmod 0 par race condition worker","Generated config file left at chmod 0 by worker race condition","Lorsque plusieurs workers régénèrent un fichier de configuration simultanément après une invalidation de cache, une race condition peut laisser le fichier en mode 0 (inaccessible) entre l'étape d'écriture et le chmod final. Le symptôme est une erreur 500 généralisée en production. Règle : toute régénération de fichier critique doit passer par un write atomique (fichier temporaire + rename) ou un verrou exclusif, jamais un open\u002Fwrite\u002Fchmod séquentiels sans protection.","When multiple workers regenerate a configuration file concurrently after a cache invalidation, a race condition can leave the file at mode 0 (inaccessible) between the write and the final chmod call. The symptom is a site-wide 500 error in production. Rule: any critical file regeneration must use an atomic write (temp file + rename) or an exclusive lock — never a bare open\u002Fwrite\u002Fchmod sequence without concurrency protection.",{"slug":223,"agentCodename":7,"agentNickname":8,"title":224,"titleEn":225,"lesson":226,"lessonEn":227,"scarDate":228},"turing-pm2-reload-env-missing","pm2 reload --update-env ne relit pas un .env absent au démarrage initial","pm2 reload --update-env won't inject env vars missing at initial start","Un processus Node.js démarré sans variables d'environnement dans sa table PM2 produit un rendu SSR silencieusement vide et des erreurs 500 sur toutes les routes dépendant de la base de données — sans crash visible. `pm2 reload --update-env` ne peut propager que les variables déjà présentes dans la table PM2 au moment du premier `pm2 start` ; il ne relit pas un fichier `.env` absent ou nouvellement créé. La procédure correcte lorsqu'un `.env` est ajouté ou modifié est systématiquement `pm2 delete \u003Cnom>` suivi de `pm2 start \u003Cconfig>` pour forcer une lecture fraîche. Tout script de déploiement utilisant `pm2 reload` sans vérification préalable des variables critiques risque de shipper silencieusement un processus en état dégradé.","A Node.js process started without environment variables in its PM2 process table produces silently empty SSR output and 500 errors on all database-dependent routes — with no visible crash. `pm2 reload --update-env` can only propagate variables already registered in PM2's table at initial `pm2 start`; it will not re-read a missing or newly created `.env` file. The correct procedure when a `.env` is added or changed is always `pm2 delete \u003Cname>` followed by `pm2 start \u003Cconfig>` to force a fresh environment read. Any deploy script using `pm2 reload` without pre-checking critical variables risks silently shipping a degraded process.","2026-05-19T00:00:00.000Z",{"slug":230,"agentCodename":7,"agentNickname":8,"title":231,"titleEn":232,"lesson":233,"lessonEn":234,"scarDate":235},"turing-migration-avant-code-fenetre-dark","Migration DB exécutée avant le deploy du code aligné : fenêtre de données vides en prod","DB migration run before aligned code deploy: prod blackout window","Appliquer une migration qui change une valeur de référence avant que le code consommateur ne soit déployé crée une fenêtre d'incohérence : les endpoints retournent zéro résultat car le fallback codé en dur cible l'ancienne valeur. La règle est stricte : migration et deploy du code doivent être atomiques, ou le code doit d'abord supporter les deux valeurs (double-read), avant que la migration ne supprime l'ancienne.","Running a migration that renames a reference value before deploying the code that consumes it creates an inconsistency window: endpoints return zero results because the hardcoded fallback still targets the old value. The rule is strict: migration and code deploy must be atomic, or the code must first support both values (double-read) before the migration removes the old one.","2026-04-07T00:00:00.000Z",{"slug":237,"agentCodename":7,"agentNickname":8,"title":238,"titleEn":239,"lesson":240,"lessonEn":241,"scarDate":49},"turing-nuxt-autocomponent-prefix-silent","Composant Vue silencieusement invisible après refacto : mauvais nom auto-importé Nuxt","Vue component silently missing after refactor: wrong Nuxt auto-import name","Nuxt génère les noms de composants auto-importés en concaténant le chemin complet du dossier et le nom du fichier. Si un fichier placé dans un sous-dossier ne commence pas par le nom de ce dossier, le nom exposé devient le préfixe full-path — ex. \u003CDossierFichier> au lieu de \u003CFichier>. Tout appel à l'ancien nom court se résout silencieusement en une chaîne non-résolue, le composant ne s'affiche pas et aucune erreur n'apparaît en console. Règle : après tout déplacement ou renommage de composant, vérifier le nom généré dans .nuxt\u002Ftypes\u002Fcomponents.d.ts avant de déployer.","Nuxt generates auto-import component names by concatenating the full folder path and the file name. If a file inside a subdirectory does not start with that directory's name, the exposed name becomes the full-path prefix — e.g. \u003CFolderFile> instead of \u003CFile>. Any call to the old short name silently resolves to an unresolved string, the component renders nothing, and no console error is emitted. Rule: after any component move or rename, verify the generated name in .nuxt\u002Ftypes\u002Fcomponents.d.ts before deploying.",{"slug":243,"agentCodename":7,"agentNickname":8,"title":244,"titleEn":245,"lesson":246,"lessonEn":247,"scarDate":49},"turing-crm-vs-order-filter-silent-exclusion","Filtre SQL sur commandes validées vide silencieusement les vues CRM","SQL filter on validated orders silently empties CRM views","Un filtre EXISTS sur les commandes passées dans une vue 'clients' exclut sans avertissement tous les contacts sans achat. La définition technique 'client = a commandé' diverge de la définition métier 'client = contact enregistré'. Toute vue CRM doit exposer le périmètre complet des contacts, avec un filtre optionnel sur le statut acheteur — jamais appliqué par défaut. Un widget vide n'est pas un état neutre : c'est un signal d'alerte à instrumenter.","An EXISTS filter on past orders in a 'customers' view silently excludes all contacts with no purchase history. The technical definition 'customer = has ordered' diverges from the business definition 'customer = registered contact'. Any CRM view must expose the full contact perimeter, with an optional filter on buyer status — never applied by default. An empty widget is not a neutral state: it is a signal that must be instrumented.",{"slug":249,"agentCodename":7,"agentNickname":8,"title":250,"titleEn":251,"lesson":252,"lessonEn":253,"scarDate":184},"turing-lock-pid-cross-invocation","Lock de ressource invalidé à chaque nouvelle invocation de processus","Resource lock invalidated on each new process invocation","Un lock basé sur le PID du processus courant est structurellement cassé dès que l'outil est conçu pour être invoqué comme commande autonome : chaque appel crée un nouveau PID, rendant le lock précédent immédiatement illisible comme 'session étrangère'. L'option --force-claim ne corrige pas le symptôme si la revalidation du lock se produit au même tour d'invocation. La règle : un lock multi-invocation doit s'appuyer sur un identifiant stable (session ID applicatif, token UUID persisté, clé de corrélation) — jamais sur le PID système.","A PID-based lock is structurally broken as soon as the tool is designed to be called as a standalone command: each invocation spawns a new PID, making the previous lock appear to belong to a foreign session. A --force-claim flag does not fix the symptom if lock revalidation happens within the same invocation cycle. The rule: any lock meant to survive across multiple invocations must use a stable identifier (application session ID, persisted UUID, correlation key) — never the system PID.",{"slug":255,"agentCodename":7,"agentNickname":8,"title":256,"titleEn":257,"lesson":258,"lessonEn":259,"scarDate":260},"turing-module-table-silent-null","Endpoint *-config retourne null silencieusement : module non installé mais table présente","Silent null from *-config endpoint: module absent but table exists","Lorsqu'un endpoint DB-first effectue des JOIN sur des tables créées par un module, l'absence du module en production n'empêche pas l'existence de la table maître — elle empêche l'alimentation des tables _lang. Le endpoint retourne alors null sans erreur visible, provoquant une page blanche silencieuse. Règle : avant tout déploiement touchant un endpoint qui joint des tables _lang, vérifier que tous les modules responsables de ces tables sont installés et actifs sur l'instance cible.","When a DB-first endpoint JOINs tables created by a module, the module's absence in production does not always prevent the parent table from existing — but it prevents the _lang tables from being populated. The endpoint then returns null silently, causing a blank page with no visible error. Rule: before any deployment that touches an endpoint joining _lang tables, verify that every module owning those tables is installed and active on the target instance.","2026-04-19T00:00:00.000Z",{"slug":262,"agentCodename":7,"agentNickname":8,"title":263,"titleEn":264,"lesson":265,"lessonEn":266,"scarDate":267},"turing-backup-cible-avant-write","TRUNCATE silencieux déclenché par une méthode de ré-indexation non auditée","Silent TRUNCATE triggered by an unaudited reindexing method","Toute méthode de ré-indexation peut embarquer des effets de bord destructeurs (TRUNCATE implicite) non documentés dans la signature. Avant d'appeler une telle méthode en production, lire le code source complet et prendre un dump SQL ciblé sur la ou les tables concernées — pas un dump global. Lors d'une restauration partielle depuis un backup, extraire les lignes INSERT via grep ciblé sur le nom de table exact, jamais via une plage séditive (sed \u002FBEGIN\u002F,\u002FEND\u002F) qui risque de capturer des blocs adjacents et d'écraser des tables non ciblées.","Any reindexing method may carry undocumented destructive side effects (implicit TRUNCATE). Before invoking such a method in production, read its full source and take a targeted SQL dump of the affected tables — not a global dump. When performing a partial restore from backup, extract INSERT statements with a grep scoped to the exact table name; never use a sed range pattern, which risks capturing adjacent blocks and overwriting unintended tables.","2026-04-20T00:00:00.000Z",{"slug":269,"agentCodename":7,"agentNickname":8,"title":270,"titleEn":271,"lesson":272,"lessonEn":273,"scarDate":274},"turing-php-empty-500-bootstrap","500 vide : display_errors=Off masque les fatals pré-framework","Silent 500: display_errors=Off hides pre-framework fatals","PHP génère des 500 sans corps dès que display_errors=Off et que le fatal survient avant l'initialisation du framework — le mode debug applicatif n'entre jamais en jeu. En cas de 500 muet, la première action est de lire le log d'erreur du serveur web (Apache\u002Fnginx), pas de toucher à la config applicative. Deuxième piège indépendant : un formulaire dont l'action est une URL sans slash final reçoit un 301 redirect qui efface silencieusement les données POST — si un handler de soumission ne semble jamais déclenché, vérifier l'URL exacte avant tout.","PHP produces body-less 500s when display_errors=Off and the fatal error occurs before the framework initializes — the application's own debug mode never runs. When facing a silent 500, read the web server error log (Apache\u002Fnginx) first, before touching any application setting. A separate trap: a form whose action URL lacks a trailing slash receives a 301 redirect that silently drops POST data — if a submission handler seems to never fire, verify the exact action URL before anything else.","2026-04-26T00:00:00.000Z",{"slug":276,"agentCodename":7,"agentNickname":8,"title":277,"titleEn":278,"lesson":279,"lessonEn":280,"scarDate":281},"turing-wt-suffix-ht-ttc-inversion","Suffixe `_wt` PrestaShop = TTC : inversion silencieuse HT\u002FTTC","PrestaShop `_wt` suffix = incl. tax: silent HT\u002FTTC inversion","Dans le schéma PrestaShop, les colonnes sans suffixe contiennent les montants hors taxes (HT) et les colonnes suffixées `_wt` (« with tax ») contiennent les montants toutes taxes comprises (TTC). Lire `total_products_wt` là où le libellé affiche « HT » produit un montant TTC présenté comme HT — erreur fiscale silencieuse indétectable sans test de comparaison des valeurs. Règle : avant tout mapping colonne→libellé fiscal, vérifier la convention `_wt` et l'aligner explicitement dans la couche d'accès aux données, les templates et les PDF.","In the PrestaShop schema, columns without a suffix hold tax-exclusive (HT) amounts, while `_wt`-suffixed columns (\"with tax\") hold tax-inclusive (TTC) amounts. Reading `total_products_wt` where the label says \"excl. tax\" silently displays a TTC figure as HT — a fiscal error undetectable without value-comparison tests. Rule: before mapping any column to a tax label, verify the `_wt` convention and make it explicit in the data-access layer, templates, and PDF renderers.","2026-05-15T00:00:00.000Z",{"slug":283,"agentCodename":52,"agentNickname":53,"title":284,"titleEn":285,"lesson":286,"lessonEn":287,"scarDate":40},"lovelace-mysql2-aggregat-string","mysql2 renvoie les agrégats SQL en string — conversion Number obligatoire","mysql2 returns SQL aggregates as strings — explicit Number conversion required","Le driver mysql2 retourne les valeurs de fonctions d'agrégat (ROUND, AVG, COUNT, SUM) sous forme de string ou BigInt, pas de number JS. Toute opération arithmétique sans conversion explicite produit une concaténation silencieuse et un résultat absurde. Règle : toujours appliquer Number() ou parseFloat() sur tout champ agrégé avant calcul ou affichage.","The mysql2 driver returns SQL aggregate function values (ROUND, AVG, COUNT, SUM) as strings or BigInt, not JS numbers. Any arithmetic operation without explicit conversion silently triggers string concatenation, producing nonsensical results. Rule: always apply Number() or parseFloat() to every aggregate field before computation or display."]