<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Olivier</title>
    <description>The latest articles on DEV Community by Olivier (@hernanz).</description>
    <link>https://dev.to/hernanz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4036001%2Faf4cba7e-a94d-45df-ad03-cb3cfbe87da9.png</url>
      <title>DEV Community: Olivier</title>
      <link>https://dev.to/hernanz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hernanz"/>
    <language>en</language>
    <item>
      <title>Découper une app métier en tranches livrables (et ne plus jamais faire de tunnel)</title>
      <dc:creator>Olivier</dc:creator>
      <pubDate>Sun, 19 Jul 2026 17:47:59 +0000</pubDate>
      <link>https://dev.to/hernanz/decouper-une-app-metier-en-tranches-livrables-et-ne-plus-jamais-faire-de-tunnel-1gp6</link>
      <guid>https://dev.to/hernanz/decouper-une-app-metier-en-tranches-livrables-et-ne-plus-jamais-faire-de-tunnel-1gp6</guid>
      <description>&lt;p&gt;Le tunnel de trois mois est le meilleur moyen de rater une application métier.&lt;/p&gt;

&lt;p&gt;On cadre, on développe, on montre à la fin. Et à la fin, l'utilisateur dit la phrase qui coûte cher : « ah, mais nous on ne fait pas comme ça. »&lt;/p&gt;

&lt;p&gt;Voici le découpage qu'on utilise pour éviter ça. Rien de révolutionnaire, mais quelques règles précises qui changent le résultat.&lt;/p&gt;

&lt;h2&gt;
  
  
  La règle de la tranche verticale
&lt;/h2&gt;

&lt;p&gt;Une tranche livrable traverse &lt;strong&gt;toute&lt;/strong&gt; la pile : base de données, logique, interface. Elle est utilisable de bout en bout par un vrai utilisateur.&lt;/p&gt;

&lt;p&gt;C'est l'inverse du découpage par couche, où l'on fait « toute la base » puis « toute l'API » puis « tout le front ». Ce découpage-là ne produit rien de testable avant la fin.&lt;/p&gt;

&lt;p&gt;❌ Semaine 1 : le schéma complet de la base&lt;br&gt;
❌ Semaine 2 : toutes les routes API&lt;br&gt;
❌ Semaine 3 : tous les écrans&lt;/p&gt;

&lt;p&gt;✅ Semaine 1 : créer une commande et la voir dans une liste — écran compris&lt;br&gt;
✅ Semaine 2 : la modifier et changer son statut&lt;br&gt;
✅ Semaine 3 : la recherche et les filtres&lt;/p&gt;

&lt;p&gt;Après la première semaine, quelqu'un peut ouvrir l'outil et faire quelque chose de réel. C'est là que remontent les vrais retours.&lt;/p&gt;
&lt;h2&gt;
  
  
  Le format de spec qui tient en un fichier
&lt;/h2&gt;

&lt;p&gt;Chaque tranche a un fichier. Toujours la même structure, et elle sert autant à l'équipe qu'à l'assistant de code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Tranche 03 — Changement de statut d'une commande&lt;/span&gt;

&lt;span class="gu"&gt;## Ce que l'utilisateur peut faire&lt;/span&gt;
Ouvrir une commande, passer son statut de "en préparation" à "expédiée",
et voir qui l'a changé et quand.

&lt;span class="gu"&gt;## Règles métier&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Seuls les rôles &lt;span class="sb"&gt;`préparateur`&lt;/span&gt; et &lt;span class="sb"&gt;`admin`&lt;/span&gt; peuvent changer un statut.
&lt;span class="p"&gt;-&lt;/span&gt; Un retour en arrière est interdit sauf pour &lt;span class="sb"&gt;`admin`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Chaque changement écrit une ligne dans &lt;span class="sb"&gt;`commande_historique`&lt;/span&gt;.

&lt;span class="gu"&gt;## Hors périmètre (important)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Pas de notification e-mail (tranche 07).
&lt;span class="p"&gt;-&lt;/span&gt; Pas d'export (tranche 09).

&lt;span class="gu"&gt;## Fini quand&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Un préparateur change un statut et voit l'historique se remplir.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Un commercial n'a pas le bouton.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Un retour en arrière est refusé avec un message clair.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La section &lt;strong&gt;Hors périmètre&lt;/strong&gt; est celle qui fait le plus de travail. Elle empêche le glissement de périmètre, qui représente couramment 30 à 50 % de charge supplémentaire sur un projet mal tenu.&lt;/p&gt;

&lt;p&gt;La section &lt;strong&gt;Fini quand&lt;/strong&gt; évite l'autre classique : le désaccord sur ce que « terminé » veut dire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pourquoi ce format marche bien avec un assistant de code
&lt;/h2&gt;

&lt;p&gt;On travaille avec Claude Code au quotidien. Ce format de fichier est celui qui donne les meilleurs résultats, pour une raison simple : un assistant échoue surtout quand le contexte est implicite.&lt;/p&gt;

&lt;p&gt;Les règles métier écrites noir sur blanc (« un retour en arrière est interdit sauf admin ») produisent du code correct du premier coup. Les mêmes règles laissées dans la tête du chef de projet produisent du code plausible et faux.&lt;/p&gt;

&lt;p&gt;Le « Hors périmètre » a un effet secondaire utile : il empêche l'assistant d'anticiper. Sans cette section, il ajoute spontanément une notification e-mail parce que ça semble logique — et vous héritez d'un code que personne n'a demandé, ni relu.&lt;/p&gt;

&lt;p&gt;Un point sur lequel on ne transige pas : les critères de « Fini quand » deviennent des tests avant d'être considérés comme validés. Environ 45 % du code généré par IA contient au moins une vulnérabilité selon les analyses publiées en 2026. Ce chiffre ne condamne pas l'outil, il rappelle juste où mettre la relecture humaine.&lt;/p&gt;

&lt;h2&gt;
  
  
  L'ordre des tranches n'est pas neutre
&lt;/h2&gt;

&lt;p&gt;On classe toujours dans cet ordre :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;La tranche qui prouve l'usage.&lt;/strong&gt; Celle qui, si elle ne convainc pas, invalide le projet entier. Elle passe en premier, quand le budget est encore intact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Les tranches à risque technique.&lt;/strong&gt; Intégration avec un système existant, import de données sales, API tierce mal documentée. Jamais à la fin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Le confort.&lt;/strong&gt; Filtres, exports, tableaux de bord. Utiles, mais aucun projet ne meurt de leur absence en semaine 4.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;L'erreur fréquente est de commencer par l'authentification et l'administration des comptes, parce que c'est « la base ». C'est trois semaines avant de montrer quoi que ce soit d'intéressant. Une authentification minimale suffit largement au départ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce que ça change concrètement
&lt;/h2&gt;

&lt;p&gt;Le bénéfice n'est pas la vitesse brute. C'est que l'erreur de cadrage se paie en une semaine au lieu de trois mois.&lt;/p&gt;

&lt;p&gt;Sur une app métier standard, ça donne une première version utilisable en 6 à 10 semaines, avec des retours utilisateurs dès la deuxième.&lt;/p&gt;

&lt;p&gt;Et surtout : le jour où le client dit « nous on ne fait pas comme ça », il le dit assez tôt pour que ça ne coûte presque rien.&lt;/p&gt;




&lt;p&gt;On détaille les étapes complètes d'un projet, les délais et les budgets réels ici : &lt;a href="https://blog.neo-va.com/creer-une-application-sur-mesure/" rel="noopener noreferrer"&gt;créer une application sur mesure&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>productivity</category>
      <category>ai</category>
      <category>french</category>
    </item>
    <item>
      <title>J'ai automatisé la production d'articles SEO avec Claude Code — et le plus important, c'est le garde-fou</title>
      <dc:creator>Olivier</dc:creator>
      <pubDate>Sun, 19 Jul 2026 05:42:07 +0000</pubDate>
      <link>https://dev.to/hernanz/jai-automatise-la-production-darticles-seo-avec-claude-code-et-le-plus-important-cest-le-421f</link>
      <guid>https://dev.to/hernanz/jai-automatise-la-production-darticles-seo-avec-claude-code-et-le-plus-important-cest-le-421f</guid>
      <description>&lt;p&gt;Google a effacé jusqu'à 80 % du trafic de sites qui publiaient du contenu IA en masse. C'est le motif &lt;em&gt;scaled content abuse&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;On voulait quand même automatiser la production d'articles. La question n'était donc pas « comment produire vite », mais &lt;strong&gt;« comment empêcher la machine de publier de la bouillie »&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Voilà l'architecture qu'on a retenue, et le morceau de code qui compte vraiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le pipeline
&lt;/h2&gt;

&lt;p&gt;Six étapes, chacune tenue par un agent Claude Code spécialisé avec son propre contexte :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Chasseur      → mine les mots-clés (questions réelles, faible concurrence)
2. Cartographe   → lit la page 1 Google, relève les questions traitées
3. Rédacteur     → écrit selon un guide de voix versionné
4. Éditeur ⛔    → contrôle qualité, BLOQUE si en dessous du standard
5. Générateur    → markdown → HTML + JSON-LD + sitemap + RSS
6. Publication   → déploiement + ping IndexNow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;L'étape 4 est la seule qui compte vraiment. Sans elle, on a juste une ferme de contenu qui se fait désindexer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le garde-fou, en code
&lt;/h2&gt;

&lt;p&gt;L'erreur classique, c'est de demander à un LLM « est-ce que cet article est bon ? ». Un modèle qui juge sa propre production est complaisant.&lt;/p&gt;

&lt;p&gt;On a donc mis un script déterministe. Pas d'IA, pas d'opinion, des mesures :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;minWords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                    &lt;span class="c1"&gt;// en dessous = contenu mince&lt;/span&gt;
  &lt;span class="na"&gt;introMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;introMax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// zone "answer-first"&lt;/span&gt;
  &lt;span class="na"&gt;minH2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                         &lt;span class="c1"&gt;// structure&lt;/span&gt;
  &lt;span class="na"&gt;minFaq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                        &lt;span class="c1"&gt;// schema FAQPage&lt;/span&gt;
  &lt;span class="na"&gt;titleMax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                     &lt;span class="c1"&gt;// au-delà, Google tronque&lt;/span&gt;
  &lt;span class="na"&gt;descMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;descMax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;175&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;banned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;                         &lt;span class="c1"&gt;// formules bannies par la charte&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dans le monde d'aujourd'hui&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;il est important de noter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en conclusion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Et les vérifications qui font sortir le script en code 1 :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// frontmatter complet&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`frontmatter: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" manquant`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// substance réelle&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;#*&amp;gt;|_`&lt;/span&gt;&lt;span class="se"&gt;\-]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minWords&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; mots (min &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minWords&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// liens internes valides — un lien mort et ça ne passe pas&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\]\((\/[&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)\/\)&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;allSlugs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`lien interne cassé: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// formules interdites&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;banned&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`formule interdite : « &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; »`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Le script de publication l'appelle en premier :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
node check.mjs      &lt;span class="c"&gt;# ⛔ sort en 1 → tout s'arrête ici&lt;/span&gt;
node build.mjs
wrangler pages deploy dist &lt;span class="nt"&gt;--project-name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;…
node indexnow.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;set -e&lt;/code&gt; + code de sortie 1 = la publication est &lt;strong&gt;structurellement impossible&lt;/strong&gt; si un article ne passe pas. Pas de « on verra », pas d'exception.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce que le garde-fou a attrapé dès le premier passage
&lt;/h2&gt;

&lt;p&gt;Sur nos trois premiers articles, écrits pourtant avec soin :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3 meta descriptions trop longues&lt;/strong&gt; (180 à 214 caractères). Google les aurait tronquées. Invisible à l'œil nu, évident pour le script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Un lien interne cassé&lt;/strong&gt; après un changement d'architecture d'URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aucun humain relisant à 23h n'aurait vu ça.&lt;/p&gt;

&lt;h2&gt;
  
  
  Les pièges rencontrés
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Le LLM juge mal son propre travail.&lt;/strong&gt; D'où le script déterministe. L'IA écrit, le code mesure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le fuseau horaire.&lt;/strong&gt; &lt;code&gt;new Date('2026-07-17T00:00:00Z').toLocaleDateString('fr-FR')&lt;/code&gt; affichait le 16 juillet. Il faut forcer &lt;code&gt;timeZone: 'UTC'&lt;/code&gt; — sinon toutes les dates de publication décalent d'un jour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le résidu de build.&lt;/strong&gt; Un dossier oublié dans le répertoire de déploiement a mis en ligne un site entier au mauvais endroit. Depuis, le script de build est le seul à écrire dans ce dossier, et on vérifie son contenu avant chaque envoi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le calibrage des règles.&lt;/strong&gt; La première version mesurait le « premier paragraphe » pour vérifier la réponse directe. Avec un style à paragraphes courts, elle criait au loup en permanence. On mesure maintenant le bloc entier avant le premier &lt;code&gt;##&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce que je retiens
&lt;/h2&gt;

&lt;p&gt;La partie difficile n'était pas de faire écrire l'IA. C'est devenu trivial.&lt;/p&gt;

&lt;p&gt;La partie difficile, c'est de &lt;strong&gt;rendre la médiocrité impossible à publier&lt;/strong&gt;. Un seuil chiffré, un code de sortie, et la discipline de ne jamais le contourner.&lt;/p&gt;

&lt;p&gt;L'autre chose : le volume ne va pas sur le domaine principal. Deux à trois articles par semaine, pas trente. Le volume part sur des plateformes à forte autorité — comme celle-ci. On automatise ce qu'on possède, on soigne à la main ce qu'on emprunte.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;On est un studio de développement. On construit des applications sur mesure et on documente ce qu'on apprend en le faisant. Si l'architecture complète vous intéresse, elle est détaillée sur &lt;a href="https://blog.neo-va.com/" rel="noopener noreferrer"&gt;notre blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
