<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Big-Picture on Ocarina — précis</title>
    <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/series/big-picture/</link>
    <description>Recent content in Big-Picture on Ocarina — précis</description>
    <generator>Hugo</generator>
    <language>fr-FR</language>
    <lastBuildDate>Thu, 04 Jun 2026 17:04:59 +0200</lastBuildDate>
    <atom:link href="https://mojo-molotov.github.io/from-ocarina-to-igor/fr/series/big-picture/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>00.01 — Cartographie de l&#39;écosystème</title>
      <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/01-ecosystem-map/</link>
      <pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/01-ecosystem-map/</guid>
      <description>&lt;h1 id=&#34;0001cartographie-de-lécosystème&#34;&gt;00.01 — Cartographie de l&amp;rsquo;écosystème&lt;a class=&#34;anchor&#34; href=&#34;#0001cartographie-de-l%c3%a9cosyst%c3%a8me&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;L&amp;rsquo;écosystème Ocarina est constitué de &lt;strong&gt;six dépôts publics&lt;/strong&gt; sur le compte&#xA;GitHub &lt;a href=&#34;https://github.com/mojo-molotov&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;code&gt;mojo-molotov&lt;/code&gt;&lt;/a&gt;. Ils s&amp;rsquo;organisent en&#xA;&lt;strong&gt;cinq rôles distincts&lt;/strong&gt; qui se composent :&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Rôle&lt;/th&gt;&#xA;          &lt;th&gt;Dépôt&lt;/th&gt;&#xA;          &lt;th&gt;Forme&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;Framework&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Bibliothèque Python publiée sur PyPI&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;Application sous test (SUT) publique&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;igoristan&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;SPA React + Vike déployée sur GitHub Pages&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;Backend de coordination&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;tests-workers&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;API Vercel Edge + Upstash Redis&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;Suite d&amp;rsquo;exemples&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina-example&lt;/code&gt; &lt;em&gt;(canonique)&lt;/em&gt;, &lt;code&gt;ocarina-with-ai-example&lt;/code&gt; &lt;em&gt;(IA)&lt;/em&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Projets Python e2e tournés vers l&amp;rsquo;Igoristan / CURA&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;Documentation publique&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina-holy-book&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Site VitePress FR + EN, PDF, skills IA&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;schéma-densemble-big-picture&#34;&gt;Schéma d&amp;rsquo;ensemble (big picture)&lt;a class=&#34;anchor&#34; href=&#34;#sch%c3%a9ma-densemble-big-picture&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────────────────────┐&#xA;│                              OCARINA (BIG PICTURE)                              │&#xA;└─────────────────────────────────────────────────────────────────────────────────┘&#xA;&#xA;   ┌──────────────────────────────┐         ┌──────────────────────────────────┐&#xA;   │  [PACKAGE]  ocarina          │ ──────► │  [PACKAGE]  ocarina-example      │&#xA;   │  Framework Python 3.14+      │   pip   │  Suite e2e contre l&amp;#39;Igoristan    │&#xA;   │  ROP / DSL / orchestration   │ install │  (Selenium + Firefox + Redis)    │&#xA;   └──────────────────────────────┘         └──────────────────────────────────┘&#xA;            │  │                                       │  ▲   │&#xA;            │  │                                       │  │  utilise&#xA;            │  │ pip install ocarina                   │  │  IGOR_API_KEY&#xA;            │  ▼                                       ▼  │   │&#xA;            │  ┌────────────────────────────────────┐  pilote │&#xA;            │  │ [PACKAGE]  ocarina-with-ai-example │  ┌──────┴──────────────────┐&#xA;            │  │ Suite e2e CURA Healthcare          │  │ [WEBSITE]  igoristan    │&#xA;            │  │ Claude Code, 99% machine           │  │ React 19 + Vike         │&#xA;            │  └────────────────────────────────────┘  │ GitHub Pages            │&#xA;            │              │                           └──────┬──────────────────┘&#xA;            │              │ pilote                           │ fetch OTP&#xA;            │              ▼                                  ▼&#xA;            │   ┌──────────────────────────────┐    ┌──────────────────────────────┐&#xA;            │   │ [WEBSITE]  CURA Healthcare   │    │ [BACKEND]  tests-workers     │&#xA;            │   │ Heroku, PHP open source      │    │ Vercel Edge Functions        │&#xA;            │   └──────────────────────────────┘    │ + Upstash Redis              │&#xA;            │                                       │ /api/otp, /otp-history,      │&#xA;            │                                       │ /api/corsicadex              │&#xA;            │                                       └──────────────────────────────┘&#xA;            │                                                 ▲&#xA;            │                                                 │ x-api-key&#xA;            │                                                 │ (IGOR_API_KEY ≡ API_SECRET)&#xA;            │                                                 │&#xA;            ▼&#xA;   ┌──────────────────────────────┐&#xA;   │  [DOCS]  ocarina-holy-book   │&#xA;   │  VitePress FR + EN + RU      │&#xA;   │  Skills IA, PDF, llms.txt    │&#xA;   │  GitHub Pages                │&#xA;   └──────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;ocarina&lt;/code&gt; → suites d&amp;rsquo;exemples&lt;/strong&gt; : dépendance Python classique (&lt;code&gt;pip install ocarina&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Suites d&amp;rsquo;exemples → SUT (Igoristan / CURA)&lt;/strong&gt; : pilotage navigateur via Selenium.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Suite Igoristan ↔ &lt;code&gt;tests-workers&lt;/code&gt;&lt;/strong&gt; : appels HTTP (OTP, Corsicadex) ; le secret partagé &lt;code&gt;IGOR_API_KEY&lt;/code&gt; (côté client) ≡ &lt;code&gt;API_SECRET&lt;/code&gt; (côté serveur).&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;responsabilités&#34;&gt;Responsabilités&lt;a class=&#34;anchor&#34; href=&#34;#responsabilit%c3%a9s&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Rôle&lt;/th&gt;&#xA;          &lt;th&gt;Contrat&lt;/th&gt;&#xA;          &lt;th&gt;Besoin&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Framework&lt;/td&gt;&#xA;          &lt;td&gt;&lt;em&gt;Donner&lt;/em&gt; le DSL, l&amp;rsquo;orchestration, la pool de drivers, les reporters&lt;/td&gt;&#xA;          &lt;td&gt;Doit être petit, auditable, sans dépendances cachées&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;SUT public&lt;/td&gt;&#xA;          &lt;td&gt;&lt;em&gt;Offrir&lt;/em&gt; un terrain de jeu volontairement chaotique (random errors, OTP, formulaires capricieux)&lt;/td&gt;&#xA;          &lt;td&gt;Hébergé en permanence sur GitHub Pages, sans backend lourd&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Backend de coordination&lt;/td&gt;&#xA;          &lt;td&gt;&lt;em&gt;Coordonner&lt;/em&gt; les workers sur l&amp;rsquo;OTP, fournir des données pour les tests parallèles&lt;/td&gt;&#xA;          &lt;td&gt;Stateless côté code, l&amp;rsquo;état vit dans Redis (Upstash)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Exemples&lt;/td&gt;&#xA;          &lt;td&gt;&lt;em&gt;Démontrer&lt;/em&gt; comment on utilise réellement Ocarina, à la fois sans IA (canonique) et avec IA (CURA)&lt;/td&gt;&#xA;          &lt;td&gt;Doivent être publics, exécutables, complets, suivis en CI&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Documentation&lt;/td&gt;&#xA;          &lt;td&gt;&lt;em&gt;Transmettre&lt;/em&gt; le pourquoi, le comment, et l&amp;rsquo;usage IA&lt;/td&gt;&#xA;          &lt;td&gt;Doit exister en EN + FR + RU (tradition corso-russe), exposer des fichiers adaptés aux LLMs comme &lt;code&gt;llms.txt&lt;/code&gt;, générer des PDF&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;trois-licences&#34;&gt;Trois licences&lt;a class=&#34;anchor&#34; href=&#34;#trois-licences&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Licence&lt;/th&gt;&#xA;          &lt;th&gt;Dépôts concernés&lt;/th&gt;&#xA;          &lt;th&gt;Pourquoi&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;MIT&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina&lt;/code&gt;, &lt;code&gt;ocarina-example&lt;/code&gt;, &lt;code&gt;ocarina-with-ai-example&lt;/code&gt;, &lt;code&gt;ocarina-holy-book&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Tout ce qui est code Python ou doc, transmissible « &lt;em&gt;tel quel&lt;/em&gt; », souverain — voir &lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/11-independence/&#34;&gt;&lt;code&gt;../11-independence/&lt;/code&gt;&lt;/a&gt;.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;ISC&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;tests-workers&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Choix par défaut du &lt;em&gt;scaffold&lt;/em&gt; Vercel Edge, conservé.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;em&gt;(aucune licence)&lt;/em&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;igoristan&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Application démo publique, hébergée par l&amp;rsquo;auteur (à considérer comme WTFPL).&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;points-de-friction-volontaires-entre-dépôts&#34;&gt;Points de friction volontaires entre dépôts&lt;a class=&#34;anchor&#34; href=&#34;#points-de-friction-volontaires-entre-d%c3%a9p%c3%b4ts&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Le design est &lt;strong&gt;volontairement asymétrique&lt;/strong&gt; sur certains axes ; ces frictions sont des outils de test :&lt;/p&gt;</description>
    </item>
    <item>
      <title>00.02 — Matrice stack / responsabilité / licence</title>
      <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/02-stack-matrix/</link>
      <pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/02-stack-matrix/</guid>
      <description>&lt;h1 id=&#34;0002matrice-stack-responsabilité-licence&#34;&gt;00.02 — Matrice &lt;em&gt;stack / responsabilité / licence&lt;/em&gt;&lt;a class=&#34;anchor&#34; href=&#34;#0002matrice-stack-responsabilit%c3%a9-licence&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Dépôt&lt;/th&gt;&#xA;          &lt;th&gt;Rôle&lt;/th&gt;&#xA;          &lt;th&gt;Langage&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;Version&lt;/th&gt;&#xA;          &lt;th&gt;Stack principale&lt;/th&gt;&#xA;          &lt;th&gt;Stack outillage&lt;/th&gt;&#xA;          &lt;th&gt;Distribution&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;Licence&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Framework de test e2e navigateur&lt;/td&gt;&#xA;          &lt;td&gt;Python&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;3.14+&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;hatchling&lt;/code&gt;, &lt;code&gt;python-docx&lt;/code&gt; (seule dépendance d&amp;rsquo;exécution), &lt;code&gt;selenium&lt;/code&gt; + &lt;code&gt;playwright&lt;/code&gt; (dev seulement)&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ruff&lt;/code&gt; (ALL), &lt;code&gt;mypy&lt;/code&gt; strict, &lt;code&gt;pytest&lt;/code&gt;, &lt;code&gt;hypothesis&lt;/code&gt;, &lt;code&gt;pytest-mypy-plugins&lt;/code&gt;, &lt;code&gt;syrupy&lt;/code&gt;, &lt;code&gt;prysk&lt;/code&gt; (cram), &lt;code&gt;allure-pytest&lt;/code&gt;, &lt;code&gt;pre-commit&lt;/code&gt;, &lt;code&gt;twine&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;PyPI, v&lt;strong&gt;1.1.10&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;MIT&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina-example&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Suite canonique e2e contre l&amp;rsquo;Igoristan&lt;/td&gt;&#xA;          &lt;td&gt;Python&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;3.14+&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina&lt;/code&gt;, &lt;code&gt;selenium ≥ 4.40&lt;/code&gt;, &lt;code&gt;python-dotenv&lt;/code&gt;, &lt;code&gt;dogpile.cache&lt;/code&gt;, &lt;code&gt;redis&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ruff&lt;/code&gt;, &lt;code&gt;mypy&lt;/code&gt;, &lt;code&gt;pre-commit&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Source uniquement&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;MIT&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina-with-ai-example&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Suite e2e CURA Healthcare co-écrite par Claude Code&lt;/td&gt;&#xA;          &lt;td&gt;Python&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;3.14+&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina ≥ 1.0.3&lt;/code&gt;, &lt;code&gt;selenium ≥ 4.40&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ruff&lt;/code&gt;, &lt;code&gt;mypy&lt;/code&gt;, &lt;code&gt;mypy-extensions&lt;/code&gt;, &lt;code&gt;typing-extensions&lt;/code&gt;, &lt;code&gt;pre-commit&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Source uniquement&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;MIT&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;igoristan&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;SUT public, application web volontairement chaotique&lt;/td&gt;&#xA;          &lt;td&gt;TypeScript&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;6.0.x&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;React 19.2&lt;/strong&gt;, &lt;strong&gt;Vike 0.4.258&lt;/strong&gt; (SSG), &lt;strong&gt;Vite 7.3&lt;/strong&gt;, &lt;strong&gt;TailwindCSS 4&lt;/strong&gt; (alpha), &lt;code&gt;valibot&lt;/code&gt;, &lt;code&gt;react-hook-form&lt;/code&gt;, &lt;code&gt;react-dropzone&lt;/code&gt;, &lt;code&gt;usehooks-ts&lt;/code&gt;, &lt;code&gt;throttleit&lt;/code&gt;, &lt;code&gt;lucide-react&lt;/code&gt;, &lt;code&gt;uuid&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;pnpm 11&lt;/code&gt;, &lt;strong&gt;Node 24&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;wireit&lt;/code&gt;&lt;/strong&gt; (orchestrateur), &lt;code&gt;eslint 9&lt;/code&gt; (flat), &lt;code&gt;prettier 3.5&lt;/code&gt;, &lt;code&gt;husky&lt;/code&gt;, &lt;code&gt;lint-staged&lt;/code&gt;, &lt;code&gt;commitlint&lt;/code&gt;, &lt;code&gt;commitizen&lt;/code&gt;, &lt;code&gt;terser&lt;/code&gt;, &lt;code&gt;rollup-plugin-visualizer&lt;/code&gt;, &lt;code&gt;vite-plugin-compression&lt;/code&gt;, &lt;code&gt;@qalisa/vike-plugin-sitemap&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;GitHub Pages (&lt;code&gt;/igoristan/&lt;/code&gt;)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&lt;em&gt;aucune&lt;/em&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;tests-workers&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Backend OTP / Corsicadex pour exercer la &lt;strong&gt;parallélisation&lt;/strong&gt; et les &lt;strong&gt;tests avec appels API&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;TypeScript&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;5.9.3&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;Vercel Edge Functions&lt;/strong&gt; (&lt;code&gt;runtime: &amp;quot;edge&amp;quot;&lt;/code&gt;), &lt;code&gt;@upstash/redis&lt;/code&gt;, &lt;code&gt;otplib&lt;/code&gt;, types &lt;code&gt;next&lt;/code&gt; (&lt;code&gt;NextRequest&lt;/code&gt;)&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;pnpm 11.x&lt;/code&gt;, &lt;code&gt;@vercel/node&lt;/code&gt; (types)&lt;/td&gt;&#xA;          &lt;td&gt;Vercel : &lt;code&gt;https://tests-workers.vercel.app&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;ISC&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina-holy-book&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Documentation publique + skills IA + PDF&lt;/td&gt;&#xA;          &lt;td&gt;TypeScript&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;6.0.x&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;VitePress 2 alpha&lt;/strong&gt;, theme &lt;code&gt;@sugarat/theme&lt;/code&gt;, &lt;code&gt;vue 3.5&lt;/code&gt;, &lt;code&gt;pagefind&lt;/code&gt;, &lt;code&gt;vitepress-plugin-image-optimize&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;pnpm 11&lt;/code&gt;, Node 24, &lt;code&gt;eslint 9&lt;/code&gt;, &lt;code&gt;prettier 3.8&lt;/code&gt;, &lt;code&gt;husky&lt;/code&gt;, &lt;code&gt;lint-staged&lt;/code&gt;, &lt;code&gt;commitlint&lt;/code&gt;, &lt;code&gt;sass-embedded&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;GitHub Pages (&lt;code&gt;/ocarina-holy-book/&lt;/code&gt;)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;MIT&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;python-early-adopter&#34;&gt;Python early adopter&lt;a class=&#34;anchor&#34; href=&#34;#python-early-adopter&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Apport Python 3.12+&lt;/th&gt;&#xA;          &lt;th&gt;Utilisation dans Ocarina&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;PEP 695&lt;/strong&gt; (&lt;code&gt;class Foo[T]:&lt;/code&gt;)&lt;/td&gt;&#xA;          &lt;td&gt;Signature générique partout (&lt;code&gt;TestSuite[Driver]&lt;/code&gt;, &lt;code&gt;Watcher[Driver]&lt;/code&gt;, &lt;code&gt;Test[Driver]&lt;/code&gt;, &lt;code&gt;Result[T]&lt;/code&gt;, &lt;code&gt;Ok[T]&lt;/code&gt;, &lt;code&gt;Thunk[T]&lt;/code&gt;, etc.)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;PEP 695 type aliases&lt;/strong&gt; (&lt;code&gt;type X = ...&lt;/code&gt;)&lt;/td&gt;&#xA;          &lt;td&gt;Tous les alias : &lt;code&gt;type Result[T] = Ok[T] | Fail&lt;/code&gt;, &lt;code&gt;type Effect = Callable[[], None]&lt;/code&gt;, &lt;code&gt;type Thunk[T] = Callable[[], T]&lt;/code&gt;, &lt;code&gt;type Mode = Literal[...]&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;&lt;code&gt;TypeGuard&lt;/code&gt;&lt;/strong&gt; (Python 3.10+)&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;is_ok&lt;/code&gt;, &lt;code&gt;is_fail&lt;/code&gt;, &lt;code&gt;is_test_result_ok&lt;/code&gt;, &lt;code&gt;is_test_result_fail&lt;/code&gt;, &lt;code&gt;is_test_result_skipped&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;&lt;code&gt;Self&lt;/code&gt;&lt;/strong&gt; (3.11+)&lt;/td&gt;&#xA;          &lt;td&gt;Retours fluides des POMs, des loggers, des invariants&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;&lt;code&gt;@final&lt;/code&gt;&lt;/strong&gt; (3.8+)&lt;/td&gt;&#xA;          &lt;td&gt;Verrouille les classes critiques (&lt;code&gt;Watcher&lt;/code&gt;, &lt;code&gt;Test&lt;/code&gt;, &lt;code&gt;TestCycle&lt;/code&gt;, &lt;code&gt;ChainRunner&lt;/code&gt;, &lt;code&gt;Ok&lt;/code&gt;, &lt;code&gt;Fail&lt;/code&gt;, …)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;&lt;code&gt;Unpack&lt;/code&gt;&lt;/strong&gt; (3.11+)&lt;/td&gt;&#xA;          &lt;td&gt;Signature de &lt;code&gt;HumanizedDriver&lt;/code&gt; côté &lt;code&gt;ocarina-example&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;&lt;code&gt;Protocol&lt;/code&gt;&lt;/strong&gt; (3.8+)&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ScreenshotDriver&lt;/code&gt;, &lt;code&gt;SupportsWrite[str]&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;&lt;code&gt;Literal&lt;/code&gt;&lt;/strong&gt; (3.8+)&lt;/td&gt;&#xA;          &lt;td&gt;Toutes les énumérations (&lt;code&gt;SeleniumCliStoreKeys&lt;/code&gt;, &lt;code&gt;LOGGERS_CHOICES&lt;/code&gt;, &lt;code&gt;Mode&lt;/code&gt;)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;&lt;code&gt;Never&lt;/code&gt;&lt;/strong&gt; (3.11+)&lt;/td&gt;&#xA;          &lt;td&gt;Signature de &lt;code&gt;_SilentArgumentParser.error&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;&lt;strong&gt;Conséquence pratique&lt;/strong&gt; : il existe un workflow CI dédié &lt;code&gt;unstable_python_full_build.yml&lt;/code&gt; qui pousse Python &lt;strong&gt;3.15-dev&lt;/strong&gt; mensuellement (&lt;code&gt;cron: &amp;quot;0 3 1 * *&amp;quot;&lt;/code&gt;), parce qu&amp;rsquo;Ocarina veut être prêt pour le prochain interpréteur dès qu&amp;rsquo;il sort. Voir &lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/10-cicd/02-ocarina-workflows/&#34;&gt;&lt;code&gt;../10-cicd/02-ocarina-workflows.md&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>00.03 — Flux d&#39;exécution global d&#39;une campagne e2e</title>
      <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/03-global-execution-flow/</link>
      <pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/03-global-execution-flow/</guid>
      <description>&lt;h1 id=&#34;0003flux-dexécution-global-dune-campagne-e2e&#34;&gt;00.03 — Flux d&amp;rsquo;exécution global d&amp;rsquo;une campagne e2e&lt;a class=&#34;anchor&#34; href=&#34;#0003flux-dex%c3%a9cution-global-dune-campagne-e2e&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;Un &lt;code&gt;python -u src/main.py …&lt;/code&gt; lancé sur l&amp;rsquo;une des deux suites&#xA;(&lt;code&gt;ocarina-example&lt;/code&gt; ou &lt;code&gt;ocarina-with-ai-example&lt;/code&gt;) déclenche cette chaîne :&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;USER  ────────────────────────────────────────────────────────────────────&#xA;       python -u src/main.py --browser firefox --workers 3 [...]&#xA;              │&#xA;              ▼&#xA;       (1) parse CLI&#xA;           CliStoreSingleton.push(create_selenium_auto_cli_store())&#xA;              │&#xA;              ▼&#xA;       (2) build pool&#xA;           create_selenium_drivers_pool(max_size=N)&#xA;              │&#xA;              ▼&#xA;       (3) warm-up dépendances externes&#xA;           - Redis (ocarina-example)&#xA;           - Heroku dyno (ai-example, via curl --retry 6)&#xA;              │&#xA;              ▼&#xA;       (4) bootstrap(&#xA;              test_cycle  = create_e2e_test_cycle(drivers_pool),&#xA;              run_plugins = lambda results: run_plugins(&#xA;                                generate_docx_proof, generate_json_results,&#xA;                                exceptions_logger=...),&#xA;              post_exec   = pretty_print_results + sys.exit(1) si fail&#xA;           )&#xA;              │&#xA;OCARINA  ─────┼──────────────────────────────────────────────────────────&#xA;              │&#xA;              ▼&#xA;       (5) TestCycle.run_all (saturate_workers=True)&#xA;              ├─ smoke_tests_campaigns      [mode : fail-fast | wait-for-all]&#xA;              │     └─ TestCampaign.run_all&#xA;              │           └─ TestSuite.run (max_workers, saturate_workers)&#xA;              │                 └─ ThreadPoolExecutor → TestFlow.run&#xA;              │                       └─ pool.acquire() → TestExecutor.execute&#xA;              │                             ├─ setup()                  (optionnel)&#xA;              │                             ├─ watchers.start()         (daemon threads)&#xA;              │                             ├─ chain_runners            (DSL Railway)&#xA;              │                             ├─ watchers.stop()&#xA;              │                             └─ teardown()               (toujours)&#xA;              ├─ campaigns (main)&#xA;              │  (skippées si un smoke a fail)&#xA;              │&#xA;SUT   ────────┼────────────────────────────────────────────────────────────&#xA;              │&#xA;              ▼&#xA;       Selenium WebDriver ⇄ navigateur réel&#xA;       parfois : OTP HTTP GET + Redis (côté ocarina-example)&#xA;              │&#xA;              ▼&#xA;       (6) run_plugins(results)&#xA;              ├─ generate_docx_proof  (lit l&amp;#39;arbre de logs, fabrique des .docx)&#xA;              ├─ generate_json_results (sérialise results en .json)&#xA;              ├─ d&amp;#39;autres si déclarés (parallélisés via ThreadPoolExecutor)&#xA;              │&#xA;              ▼&#xA;       (6&amp;#39;) post_exec(results)&#xA;              ├─ pretty_print_results (ANSI, hiérarchique)&#xA;              └─ has_test_cycle_failed → sys.exit(1) le cas échéant&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;détail-des-étapes&#34;&gt;Détail des étapes&lt;a class=&#34;anchor&#34; href=&#34;#d%c3%a9tail-des-%c3%a9tapes&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;1-parse-cli&#34;&gt;(1) Parse CLI&lt;a class=&#34;anchor&#34; href=&#34;#1-parse-cli&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;create_selenium_auto_cli_store()&lt;/code&gt; détecte l&amp;rsquo;OS via &lt;code&gt;platform.system()&lt;/code&gt; :&lt;/p&gt;</description>
    </item>
    <item>
      <title>00.04 — Relations entre les six dépôts</title>
      <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/04-repo-relations/</link>
      <pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/00-big-picture/04-repo-relations/</guid>
      <description>&lt;h1 id=&#34;0004relations-entre-les-six-dépôts&#34;&gt;00.04 — Relations entre les six dépôts&lt;a class=&#34;anchor&#34; href=&#34;#0004relations-entre-les-six-d%c3%a9p%c3%b4ts&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;Chaque arête du graphe est un &lt;em&gt;contrat&lt;/em&gt; : un secret, une URL, un type de payload, ou une version. On les détaille ici, par paire.&lt;/p&gt;&#xA;&lt;h2 id=&#34;ocarina--ocarina-example&#34;&gt;&lt;code&gt;ocarina&lt;/code&gt; ↔ &lt;code&gt;ocarina-example&lt;/code&gt;&lt;a class=&#34;anchor&#34; href=&#34;#ocarina--ocarina-example&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Direction&lt;/th&gt;&#xA;          &lt;th&gt;Mécanisme&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina&lt;/code&gt; → &lt;code&gt;ocarina-example&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;pip install ocarina&lt;/code&gt; depuis PyPI&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina-example&lt;/code&gt; → &lt;code&gt;ocarina&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Aucune (l&amp;rsquo;exemple ne pousse rien)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;L&amp;rsquo;exemple &lt;strong&gt;écrit ses propres adapters&lt;/strong&gt; au-dessus du framework :&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;lib/ext/ocarina/adapters/agnostic/act.py&lt;/code&gt; → ajoute le hook &lt;code&gt;on_failure&lt;/code&gt; qui transforme une page d&amp;rsquo;erreur HTTP (titre matché par &lt;code&gt;ERROR_PAGE_REGEX&lt;/code&gt;) en &lt;code&gt;HttpErrorPageReachedError&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;lib/ext/ocarina/adapters/agnostic/match_page.py&lt;/code&gt; → &lt;code&gt;create_match_page(raised_exceptions=transient_errors)&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;lib/ext/ocarina/adapters/agnostic/env_getters.py&lt;/code&gt; → typed &lt;code&gt;EnvGetters[_CredsKeys, _ValuesKeys]&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;lib/ext/ocarina/adapters/selenium/test_suite.py&lt;/code&gt; → fige &lt;code&gt;max_retries_per_test=8&lt;/code&gt;, &lt;code&gt;transient_errors=...&lt;/code&gt;, &lt;code&gt;autoscreen_on_fail=True&lt;/code&gt;, propage &lt;code&gt;--only&lt;/code&gt;/&lt;code&gt;--exclude&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;lib/ext/ocarina/adapters/selenium/test_campaign.py&lt;/code&gt; → fige &lt;code&gt;max_workers=get_max_workers()&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;ocarina--ocarina-with-ai-example&#34;&gt;&lt;code&gt;ocarina&lt;/code&gt; ↔ &lt;code&gt;ocarina-with-ai-example&lt;/code&gt;&lt;a class=&#34;anchor&#34; href=&#34;#ocarina--ocarina-with-ai-example&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;pip install . ruff mypy mypy-extensions typing-extensions pre-commit&lt;/code&gt; car l&amp;rsquo;exemple IA a la dépendance fixée dans son &lt;code&gt;pyproject.toml&lt;/code&gt; : &lt;code&gt;ocarina&amp;gt;=1.0.3&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;L&amp;rsquo;adapter &lt;code&gt;act&lt;/code&gt; est &lt;strong&gt;minimaliste&lt;/strong&gt; ici : pas de &lt;code&gt;on_failure&lt;/code&gt; (CURA n&amp;rsquo;a pas de page d&amp;rsquo;erreur volontairement aléatoire à intercepter). Voir &lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/08-ai-example/&#34;&gt;&lt;code&gt;../08-ai-example/&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;L&amp;rsquo;adapter &lt;code&gt;create_drivers_pool&lt;/code&gt; est &lt;strong&gt;surchargé&lt;/strong&gt; pour bâtir un Chrome &lt;em&gt;clean&lt;/em&gt; (password manager off, leak detection off). Voir &lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/08-ai-example/06-data-gaps/&#34;&gt;&lt;code&gt;../08-ai-example/06-data-gaps.md&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;ocarina-example--igoristan&#34;&gt;&lt;code&gt;ocarina-example&lt;/code&gt; ↔ &lt;code&gt;igoristan&lt;/code&gt;&lt;a class=&#34;anchor&#34; href=&#34;#ocarina-example--igoristan&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Direction&lt;/th&gt;&#xA;          &lt;th&gt;Contrat&lt;/th&gt;&#xA;          &lt;th&gt;Détail&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ocarina-example&lt;/code&gt; → &lt;code&gt;igoristan&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;URLs publiques&lt;/td&gt;&#xA;          &lt;td&gt;Tout passe par &lt;code&gt;https://mojo-molotov.github.io/igoristan/&amp;lt;route&amp;gt;&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;igoristan&lt;/code&gt; → &lt;code&gt;ocarina-example&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;aucun (le SUT ne sait pas qu&amp;rsquo;il est testé)&lt;/td&gt;&#xA;          &lt;td&gt; — &lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;code&gt;src/constants/pages/&lt;/code&gt; :&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
