You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[EPIC] Traduction multilingue du depot via datasetupdater Argumentum (low priority) #1650
État mesuré au 2026-10-11 (lane myia-po-2024:CoursIA, tranche acceptance 4 de #13906)
1. Les six PRs du bloc du 10-05 ci-dessous sont toutes MERGÉES (vérifié firsthand 11/10) : #19118 (2026-10-05), #19128 (2026-10-05), #19107 (2026-10-04), #18928 (2026-10-03), #19083 et #19110 (2026-10-04) — les statuts « attente merge coord / re-tampon adjoint » de cette table sont périmés.
9e paire de traduction (EXPECTED_PAIR_COUNT 8 -> 9) — corrige le rouge de base #19996
La séquence 4 du 2026-09-22 reste le plan à exécuter ; aucune de ces PRs ne ferme #1650.
Portée du non-vérifié : fenêtre de l'organe = 2026-10-04 -> 10-10 ; le contenu cellule-par-cellule des rendus _en n'a pas été relu ici.
État mesuré au 2026-10-05 — consolidation de la posture (#1650)
Ce bloc préfixe sans refermer l'issue. La posture est contredite sur deux points, et cinq PRs livrées par le cluster (Octobre) ne sont pas consignées dans le corps ci-dessous.
Posture contredite -- deux points :
Suffixe canonique des notebooks pilotant un noyau Lean : la décision 4.1 du 2026-09-22 annonçait un suffixe -Lean-Python (au moins 36 notebooks Python pilotent Lean, aucun suffixé). L'audit de suffixe livré par Rename(#1650): Serre100 08 suffixe -Lean — audit de suffixe Serre100+Langlands #19128 (relecture par mes soins, 2026-10-04) contredit ce point : un seul notebook (Serre100/08) pilote un noyau lean4-wsl natif, donc suffixe -Lean. Les 16 autres notebooks de l'audit sont Python stdlib pur sans exécution Lean, donc pas de suffixe. Le suffixe -Lean-Python était une hypothèse, pas un constat. La convention canonique désormais est -Lean (kernel natif) | rien (Python pur), voir la cadence des notebooks Lean-16b/c.
Organe de parité : la décision 3 indiquait « modèle à réutiliser plutôt que réinventer : la parité jumeaux Python/C# — registre de paires avec empreintes de contenu, attestation, audit de dérive (scripts/notebook_tools/check_twin_parity.py, twin-parity*.yml) ». L'organe est désormais livré par Add(ci,#19116): twin-parity-guard -- parite jumeau FR/<lang> scopee au diff de la PR #19118 (twin-parity opérationnel, 2026-10-04). La décision 3 devient donc « s'appuyer sur l'organe livré » et la phase « harnais de localisation » peut s'inspirer directement du registre twin-parity.
Cinq PRs non consignées dans le corps ci-dessous :
Portée vérifiée : la correction de la posture ne touche ni le mandat user 2026-05-28 (« traduire simplement le contenu du dépôt en anglais et en plusieurs autres langues ») ni la décision d'architecture de distribution (1 dépôt par langue). Elle met à jour la séquence 4.1 (suffixe) et la phase 4 (organe twin-parity livré). L'issue reste OPEN, pas de See #N vers un travail de fermeture : aucun des 5 PRs ci-dessus ne ferme #1650, et la séquence 4 du 2026-09-22 reste le plan à exécuter.
Mandat utilisateur (verbatim)
"Traduire tout simplement le contenu du dépôt en anglais et en plusieurs autres langues.
C'est un travail pharaonique mais il se trouve qu'en ce moment même Argumentum utilise un outil développé par mes soins l'an dernier pour traduire toutes les contenus du jeu dans des csv massifs.
Je pense qu'après completion de l'issue qui mandate son intégration dans le dépôt en sous-module, on pourra se servir du même moteur pour faire la traduction en un script global. Création des csv à traduire à partir des cellules de notebook et des paragraphes de markdown, exécution du datasetupdater d'argumentum dans toutes les langues actuellement supportées par argumentum (cf le dashboard pour le travail en cours), puis redispatching dans des notebooks xxx_en.ipynb, xxx_es.ipynb etc. Pareil pour les readme et autres docs."
— jsboige, 2026-05-28, à ai-01:CoursIA (low priority, troisième Epic dans la série Conway #1647 / Grothendieck #1646 / Traduction)
Décisions user du 2026-09-22 — architecture de distribution (remplacent les arbitrages des Phases 2, 3 et 4)
Discussion stratégique ai-01 ↔ user du 2026-09-22. Verbatims :
« le caractère beta des notebooks ne me semble pas être un blocage complet au fait qu'on avance sur le sujet de la localisation »
« Non on doit traduire le code, il sera exécuté dans chacun des dépôts localisés »
« je pense qu'il faut qu'on accepte la possibilité de PRs localisées. On a normalement spécifié un système de comparaison des csv et des cellules de notebook pour détecter les évolutions, il faudra juste prévoir que ce système fasse la comparaison entre dépôts distincts. On doit pouvoir s'inspirer de ce qui est fait pour la parité Python/Csharp. »
« OK pour renommer avant de traduire »
1. Un dépôt de distribution par langue — pas de siblings xxx_<lang>.ipynb, pas de fork, pas de LFS
Mesure du 2026-09-22 : le dépôt pèse ~2,8 Go d'historique sur GitHub (104 forks) ; les 1 371 notebooks de l'arbre courant font 639 Mo (médiane 96 Ko, les 5 plus gros GenAI Audio/Image = 124 Mo). Sept langues cibles en siblings = +4,5 Go d'arbre courant dès la première vague, puis chaque ré-exécution multipliée par 8. GitHub recommande de rester sous 5 Go.
Option
Verdict
Motif
Siblings xxx_<lang>.ipynb dans CoursIA
écartée
explosion de taille ci-dessus
Fork par langue
écartée
un fork embarque tout l'historique du parent (aucun gain au clone) ; resynchroniser N forks à chaque correction FR = conflits permanents ; forks relégués dans la recherche GitHub
Git LFS pour les notebooks
écartée
le notebook devient un pointeur : diff de PR et organes de review (ratchets sortie/source, validate_pr_notebooks) aveugles ; contributeur sans git-lfs = notebooks cassés ; bande passante facturée au propriétaire ; alléger l'existant exigerait de réécrire main (interdit). LFS reste pertinent pour de vrais binaires à venir (dll/exe/pt/pdf)
Dépôt séparé par langue (CoursIA-en, CoursIA-es, …)
retenue
CoursIA reste la source FR et ne porte que la mémoire de traduction (translations/, texte) ; chaque dépôt de langue ≈ taille d'un instantané ; README natif, topics, site indexable dans sa langue
2. Le code est traduit et exécuté dans chaque dépôt localisé
Remplace « le code lui-même n'est jamais traduit » (Phase 2) et « conserve execution_count et outputs du source » (Phase 3). Chaque notebook localisé porte ses propres sorties d'exécution réelle (C.2 s'applique dans chaque dépôt de langue, comme ici). Conséquence de chantier : l'extracteur doit couvrir identifiants, chaînes affichées, commentaires et légendes, avec une garde qui vérifie que le code traduit s'exécute (la parité de comportement se mesure à l'exécution, pas au diff).
3. PRs localisées acceptées — comparaison entre dépôts distincts
Une contribution peut arriver dans un dépôt de langue. L'organe de détection d'évolution (CSV par série de #4957, scripts/translation/check_translation_sync.py et ses 6 verdicts, multilingual_drift_audit.py) doit comparer entre dépôts, et non plus seulement à l'intérieur de CoursIA. Modèle à réutiliser plutôt que réinventer (organ-first) : la parité jumeaux Python/C# — registre de paires avec empreintes de contenu, attestation, audit de dérive (scripts/notebook_tools/check_twin_parity.py, twin-parity*.yml). Une paire devient (notebook FR @ sha, notebook <lang> @ sha, dépôt) ; une évolution d'un côté se propage vers l'autre par PR, dans les deux sens.
4. Séquence
Renommer avant de traduire : numérotation, suffixe -Lean-Python (au moins 36 notebooks Python pilotent Lean, aucun suffixé), casse du suffixe C# (96 -Csharp vs 34 -CSharp), consolidation des lakes — la mémoire de traduction est indexée par chemin + cell_id, tout renommage postérieur casse les clés dans chaque langue.
READMEs à jour (ils listent des chemins).
Harnais de localisation (connecteur datasetupdater, génération, exécution, publication, comparaison inter-dépôts) — pas gaté par le caractère beta des notebooks.
Insight pivot — un moteur unique, trois couches CoursIA
Le datasetupdater d'Argumentum existe déjà et tourne en production sur le jeu Argumentum. CoursIA ne réinvente rien : on connecte. Le travail réel se réduit à modeler le contenu pédagogique en CSV équivalent à un dataset Argumentum, puis à redéposer le résultat traduit dans la forme attendue (notebook ou markdown).
Dépendance bloquante — LEVÉE le 2026-06-09, remplacée par trois gates qui vivaient en commentaires
Ce que cette section disait jusqu'au 2026-09-01 :« #1271 doit être mergé avant Phase 1. État actuel (dashboard 2026-05-26) : GELÉ pending feu vert user post-PrCon. »
C'est faux depuis près de trois mois.#1271 est CLOSED le 2026-06-09, et le sous-module Argumentum est présent sur main à MyIA.AI.Notebooks/SymbolicAI/Argument_Analysis/Argumentum (git ls-tree origin/main, gitlink 1c5231f6, vérifié le 2026-09-01). Le datasetupdater est atteignable. Une lane qui tirait cette EPIC lisait « GELÉ », concluait qu'elle était bloquée sur autrui, et la reposait — c'est le mécanisme de délaissement que #11900 décrit, et il a tourné ici pendant 84 jours.
Les trois gates réels — ils existent, mais ils ne sont pas celui-là
Aucun ne bloque le moteur ; tous les trois bloquent la production de traductions. La distinction est ce qui rend cette EPIC de nouveau piochable.
Revue éditoriale, par notebook signé — [EPIC] Revue editoriale user — gater PRODUCTION sur une signature reelle, un dossier a la fois #11259 (OPEN). Mandat user du 2026-08-16, inscrit dans un commentaire de cette issue : « [la revue éditoriale] c'est le vrai gate qui permettra de lancer la traduction 8 langues sans avoir l'impression de créer [du volume non relu] ». La traduction se déclenche par notebook signé, jamais par vague.
Consolidation avant traduction — décision user du 2026-08-31/09-01, après parcours navigateur de la série GameTheory : « On lancera la trad après consolidation. » GameTheory est la série nommée en premier.
translation_golden_set.json n'existe pas (find du 2026-09-01) — c'est le seul sous-critère de la Phase 0.5 qui n'est pas livré, et il est petit : indexer les paires FR/EN déjà produites par le défrichage manuel. C'est le grain le plus immédiat de cette EPIC, et il pré-remplit l'étalonnage de la Phase 4.
Les phases ci-dessous conservent leur rédaction d'origine ; leur état réel est celui du tableau ajouté en tête de la section « Phases ».
État des phases au 2026-09-01 (ai-01) — le plan ci-dessous n'avait jamais été coché
Phase
État mesuré
Preuve
0 — Prérequis & inventaire
LIVRÉE
inventaires intégrés au body
0.5 — Défrichage manuel EN→FR
LIVRÉE, sauf le golden set
#7490 (conway-lean patterns), #8717 (scripts/datasets), plus la vague FR-first (#9618, #9645, #9761). translation_golden_set.jsonabsent
1 — Connecteur Argumentum
DÉBLOQUÉE, non commencée
sous-module présent sur main depuis #1271 (CLOSED 2026-06-09)
2 — Extracteur CSV
LIVRÉE pour l'essentiel
extract_cells_to_csv.py + 37 tests (#9265) ; ~20 séries dans translations/
Le plan d'origine séquençait tout derrière « #1271 puis le moteur ». Le plateau a fait l'inverse : le moteur est construit, c'est la production qui est tenue — délibérément, par des décisions user. Lire les phases dans l'ordre du plan induit en erreur ; lire ce tableau ne le fait pas.
Bornes coût observées Argumentum : ~$8/PR garde-fou, ~$120 cumul sur une Phase complète (~1500 cellules)
Maturité prouvée 2026-05-28 (Phase 3 Scenarii ES/FA/AR 100% en 1 cycle, ratio API ~1.0×/cell post-fix tool description) — moteur prêt pour reuse externe
Cette liste est la source de vérité : toutes les langues vivantes côté Argumentum sont produites côté CoursIA, ni plus, ni moins. Si Argumentum ajoute DE/IT/JA en v1.0, CoursIA suit en cycle suivant.
Phase 0.5 — Défrichage manuel ad-hoc EN→FR (4-8h, déblocable maintenant, sans Argumentum)
Ajouté 2026-06-12 suite mandat user (« commence par identifier et traduire en français de façon ad-hoc, non scriptée, les nombreux docs markdown profonds encore en anglais, en récupérant au passage les versions anglaises en README.en.md telles que visées par la résolution scriptée »). C'est un prélude au moteur Argumentum, pas le moteur lui-même — pas besoin d'en connaître le détail pour exécuter cette phase.
Rationale (pourquoi avant la Phase 1 scriptée).
Préalable à l'exécution du moteur. Le datasetupdater Argumentum part des sources françaises pour générer les autres langues. Or un scan du dépôt (2026-06-12) révèle que ~30 docs markdown profonds sont encore en anglais alors que le dépôt est FR-primaire (CLAUDE.md §E). Si le moteur tourne sur un mélange EN/FR incohérent, il traduira de l'anglais vers les autres langues sur ces fichiers, ou produira un mélange. Il faut donc assainir les sources FR d'abord.
Pré-produit les *.en.md. La manœuvre récupère l'original EN comme <doc>.en.md au passage — exactement le livrable que la Phase 3 scriptée générerait automatiquement plus tard. Le défrichage manuel pré-remplit donc le périmètre EN.
Golden set pour le moteur. Les paires FR/EN de qualité humaine produites ici servent de jeu d'étalonage/audit pour valider la qualité du moteur Argumentum en Phase 4 (cf critère ajouté).
Convention naming. Alignement sur l'Epic existant (Phase 3) : README.en.md, <name>.en.md (séparateur point, standard i18n, cohérent avec xxx_<lang>.ipynb). Note : le mandat user écrit Readme_en.md (underscore) ; on standardise sur README.en.md pour cohérence avec la Phase 3 déjà documentée — à confirmer par le user si l'underscore est préférable.
Périmètre issu du scan 2026-06-12 (docs EN-dominants, ratio stop-words EN/FR > 0.60, >100 mots), filtré pour ne garder que les docs CoursIA pérennes :
Catégorie
Docs EN profonds (chemins représentatifs)
READMEs de stratégies QC
QuantConnect/projects/{DualMomentum,PairsTrading,TrendFilteredMeanReversion,composite-c1-multiasset,composite-c2-equityfactor,Mamba-Crypto-Ranking,ML-Classification,Research-Executor,Framework_Composite_FamaFrenchAllWeather}/README.md (≈10 fichiers, ~120-380 mots chacun)
Commit atomique par série (règle catalog-pr-hygiene HARD 3) : une PR = une série (ex. « traduit les READMEs EN des stratégies QC », « traduit Probas/PORT_PYTHON_PLAN.md »). Pas de composite cross-séries.
Indexer la paire dans un translation_golden_set.json (source FR + source EN + chemin) pour réutilisation Phase 4.
Cette phase produit des fichiers *.en.md qui seront réconciliés avec la sortie du moteur en Phase 3 : si le moteur régénère un .en.md quasiment identique à la version humaine, c'est un signal de qualité ; un écart signale une zone à auditer.
Phase 1 — Connecteur Argumentum → CoursIA (4-6h)
scripts/translation/argumentum_bridge.py :
Wrapper Python autour du datasetupdater Argumentum
Importation verbatim du datasetupdater : pas d'altération (cf principe paternité externe).
Phase 2 — Extracteur CSV (8-12h)
scripts/translation/notebook_to_csv.py :
Lit un .ipynb, parcourt les cells
Cellules markdown : extrait chaque paragraphe en ligne CSV
Préserve formules LaTeX $...$ et $$...$$ (placeholders __LATEX_0__, etc.)
Préserve liens markdown (texte traduit, URL conservée)
Préserve blocs code inline ` (placeholders)
Cellules code : extrait uniquement les commentaires # / // (les strings restent en français quand elles font partie de la pédagogie ; le code lui-même n'est jamais traduit)
Stratégie "fichiers précieux mis en avant" — Argumentum
Le datasetupdater Argumentum est un outil utilisateur (jsboige) précieux. Il doit être :
Cité publiquement dans le README racine CoursIA :
"Translations powered by Argumentum datasetupdater — multilingual CSV translation engine developed by jsboige (2024-2025)."
Crédité dans le docstring de argumentum_bridge.py :
"""Bridge to Argumentum datasetupdater (jsboige, 2024-2025).Multilingual CSV translation engine originally developed for theArgumentum card game corpus.Source: https://github.com/jsboige/ArgumentumSubmodule path: <chemin>Bridge integration date: <YYYY-MM-DD>"""
Importé verbatim : pas d'altération du datasetupdater côté CoursIA. Toute adaptation va dans le bridge, jamais dans le sous-module.
Documenté dans une page dédiée docs/translation-engine.md :
Description du pipeline CoursIA
Crédit moteur Argumentum
Liste des langues actives
FAQ retraduction / drift / contribution
Hall of Fame
Acteur
Contribution
Date
jsboige
Argumentum + datasetupdater — moteur de traduction multilingue
2024-2025
Argumentum corpus
Dataset originel ayant servi à éprouver le datasetupdater
2024-2025
Langues activées
Héritées de la matrice Argumentum à la date d'exécution (cf dashboard Argumentum live)
continu
Set confirmé Argumentum Data-Gate v0.9.0 (relevé dashboard Argumentum workspace 2026-05-28) : EN, FR, ES, AR, FA, ZH, RU, PT (8 langues, 4 datasets matures : Rules / Virtues / Scenarii / Fallacies). Backend gpt-5.5, garde-fou ~$8/PR, plafond ~$120/Phase. Si Argumentum v1.0 ajoute DE / IT / JA, CoursIA suit en cycle suivant — la matrice Argumentum reste la source de vérité.
Sources FR assainies (Phase 0.5) : les ~30 docs EN profonds pérennes sont traduits en FR (source primaire) avec leur original EN récupéré en <doc>.en.md ; translation_golden_set.json constitué
Golden set réutilisé (Phase 4) : la qualité du moteur Argumentum est auditée par comparaison avec le golden set Phase 0.5 (écart mesuré)
≥1 série entière traduite et publiée (Phase 4 pilote)
Driver batch fonctionnel et reproductible (Phase 5)
Dashboard Argumentum workspace — source de vérité langues supportées
Mémoires de session : feedback-community-witnesses-credited (paternité du datasetupdater), feedback-mandate-amplification ("pharaonique mais réutilisation cleane" = scope assumé)
🤖 Generated with Claude Code pour ai-01:CoursIA cycle 92, suite mandat user 2026-05-28.
Corrections vérifiées (2026-08-30 — tri ROO-1, réfutations Vibe)
Volumétrie : l'estimation « ~400 notebooks » (ligne inventaire) est réfutée — 1 181 notebooks source mesurés sur origin/main (SHA 68e7a663, git trees truncated:false, exclusions _output/_<lang>), cohérent avec le README (« 1 024 notebooks » au 17/08) et l'audit Vibe (1 011 le 29/08). Toute projection de coût/temps doit se recalculer sur ~1 200, pas 400.
Schéma CSV divergent de l'existant : le corpus translations/ (33 CSV, 804 notebooks couverts selon l'audit) utilise déjà notebook,cell_id,cell_type,src_lang,src_hash,text_fr,text_en,text_es,text_ar,text_fa,text_zh,text_ru,text_pt,hash_*,translate_policy — vérifié sur translations/genai/audio.csv (origin/main). Le schéma proposé dans cette issue (notebook_path,paragraph_idx,placeholders_json) n'existe nulle part dans le corpus et ignorerait 7 colonnes de langues + les colonnes hash_* de détection de changement. Toute implémentation doit partir du schéma existant.
Enrichissement — ajout Phase 0.5 (défrichage manuel EN→FR)
Suite mandat user 2026-06-12 (« commence par identifier et traduire en français de façon ad-hoc, non scriptée, les nombreux docs markdown profonds encore en anglais, en récupérant au passage les versions anglaises en README.en.md telles que visées par la résolution scriptée »).
Ligne d'estimation ajoutée ; 2 critères de complétion (sources FR assainies + golden set réutilisé Phase 4).
Rationale courte : le datasetupdater Argumentum part des sources FR. Or ~30 docs markdown profonds sont encore en EN dans un dépôt FR-primaire (CLAUDE.md §E) — scan 2026-06-12. Si on laisse le moteur tourner sur ce mélange, il traduira de l'anglais vers les autres langues sur ces fichiers. Il faut donc assainir les sources FR avant la Phase 1, et cette étape ne dépend pas du sous-module Argumentum gelé.
Bonus : la manœuvre pré-produit les *.en.md (le livrable de la Phase 3 scriptée) et constitue un golden set FR/EN humain pour auditer la qualité du moteur en Phase 4.
Infra : scripts/{qc-mcp-lite,datasets}/README.md, docker-configurations/notebook-runner/README.md
À confirmer par le user : convention naming README.en.md (point, alignée sur la Phase 3 existante) vs Readme_en.md (underscore du mandat). J'ai standardisé sur le point pour cohérence.
Découpage : PRs atomiques par série (cf catalog-pr-hygiene HARD 3). N'exécute pas maintenant — backlog enrichment seul.
User a réactivé la Phase 0.5 (« avant la traduction, faire en sorte qu'on ait tout en français »). Décisions arrêtées :
Séparateur naming = point : README.en.md (la note "underscore vs point" du body est tranchée → point, standard i18n, cohérent avec la Phase 3 scriptée). Notebooks restent xxx_en.ipynb.
Périmètre = pédagogique uniquement (~15) docs de série/sous-projet à nous (recensement filtré : 123 EN-dominants bruts → ~27 à nous → ~15 pédagogiques après exclusion scripts/infra). Hors scope confirmé : vendored foundry-lib/lib/**, data QC ESGF-2026/.../data/**, stubs QC projects/*, lakes externes, fork Z3.Linq.
Cadence = lane dédiée side-track (n'interrompt pas Lean profondeur / QC).
Issue fille = #3870 (liste partitionnée Lean/QC + mécanique git mv → README.en.md + nouveau FR).
Flux verrouillé : nouvelle règle .claude/rules/readme-french-first.md — tout contenu doc ajouté = FR, jamais "match the surrounding English" (cause racine du re-engendrement de contenu anglais via les Conclusions #2651). C'est le complément process : on arrête d'en créer pendant qu'on résorbe le stock.
Phases 1+ (moteur Argumentum scripté) restent gated par #1271.
Tranche « renommer avant de traduire » : mesure du 2026-10-05 — un blocage de norme avant tout renommage
Pris en charge par la lane myia-ai-01:CoursIA-2 sur mandat coordinateur. Aucun renommage n'a ete pose : la mesure montre que la norme est contradictoire entre deux sources autoritatives, et qu'une partie de la tranche est deja couverte par une PR ouverte. Poser les noms dans cet etat serait un geste aveugle.
Deux documents autoritatifs ne disent pas la meme chose
Source
Ce qu'elle dit du vocabulaire de noyau
.claude/rules/notebook-accretion-numbering.md:15 — arbitrage du mainteneur du 2026-09-25
« -Python, -CSharp, -Lean, ou -Lean-Python pour un notebook Python qui pilote reellement Lean (sous-processus lake/lean, REPL, lecture d'un lake) »
scripts/notebook_tools/kernel_suffix_canon.json (champ _canon, consomme par check_kernel_suffix_canon.py)
« Casse canonique pour les suffixes de noyau : -CSharp et -Python. -Lean n'est PAS un suffixe de noyau dans ce depot (il marque le contenu ; le pendant Lean porte -Native) »
Deux vocabulaires incompatibles pour la meme famille, et les deux vivent dans l'arbre :
-Lean (30) et -Native (11) coexistent, alors que le canon du garde declare -Lean hors vocabulaire et -Native canonique — soit l'inverse du poids mesure. Une serie entiere porte les deux a quelques numeros d'ecart : Lean-16b-Conway-Game-of-Life-Lean.ipynb cotoie Lean-16d-Conway-Game-of-Life-Lean-Native.ipynb.
Ce que le garde en fait, mesure sur l'arbre
python scripts/notebook_tools/check_kernel_suffix_canon.py --scan-all --json : 1489 carnets examines, 7 constats — et ils se repartissent en trois classes qui ne se traitent pas pareil :
6 carnets Tweety (-Lean sur noyau python3) : deja couverts par la PR ouverte rename(#16231): Tweety etape 1 -- suffixe de noyau (11 notebooks) + referents (47 fichiers) #19150 (rename(#16231): Tweety etape 1 -- suffixe de noyau (11 notebooks) + referents (47 fichiers)). Le garde de collision L898 les ecarte — les renommer ici produirait la double-livraison que la garde existe pour empecher.
Lean-16b-Conway-Game-of-Life-Lean.ipynb (noyau python3-lean, 9 appels lake / 26 lean / 5 repl dans le code) : c'est le cas central de la contradiction. Sous la regle §1 il devrait porter -Lean-Python (Python qui pilote Lean) ; sous le canon du garde, -Lean n'existe pas et l'attendu serait -Python — ce qui serait faux pour un carnet Lean.
Workbook-Template-Python.ipynb (GenAI/SemanticKernel) : noyau .net-csharp avec #!connect jupyter --kernel-spec python3. Polyglotte assume : le suffixe decrit le contenu, le noyau est .NET. Aucun renommage n'a de sens ici — c'est le garde qui lit une seule des deux dimensions.
Demande
Arbitrage du vocabulaire avant la tranche, pas apres : -Lean (regle, signee) ou -Native (canon du garde) — et, si -Native l'emporte, la regle §1 doit etre amendee dans le meme geste, sinon chaque sweep futur rejouera ce blocage. Le reste de la tranche (casse Csharp/CSharp, numérotation) n'est pas concerne par ce point et reste prenable.
Ce constat n'est pas un refus de travail : c'est la mesure qui evite de renommer 30 carnets sous une norme que deux sources autoritatives contredisent, alors que le renommage est precisement l'operation dont la memoire de traduction depend (#1650 : « tout renommage posterieur casse les cles dans chaque langue »).
Arbitrage coordinateur sur le constat c.5985117439 (deux vocabulaires du suffixe de noyau) : -Lean est canonique.
La règle notebook-accretion-numbering.md §1 (arbitrage du mainteneur du 2026-09-25, commit af598aca40) est la source la plus récente. Elle dit que le suffixe nomme le noyau : -Python, -CSharp, -Lean (noyau Lean 4), -Lean-Python (noyau Python qui pilote réellement Lean). -Native n'y figure pas.
Le texte _canon de scripts/notebook_tools/kernel_suffix_canon.json (2026-09-12, retouché le 2026-09-24) est antérieur à cette règle : il est périmé. Il se réaligne, avec la docstring de check_kernel_suffix_canon.py, dans la PR de la tranche. C'est une dette d'outil, pas un changement de norme.
Dans la tranche, c'est le kernelspec de chaque carnet qui décide, pas son suffixe actuel :
-Lean-Native sous noyau Lean devient -Lean ;
un -Lean hérité sous noyau Python devient -Lean-Python s'il pilote lake, lean ou le REPL, et -Python sinon ;
[CLAIMED] lane myia-po-2027:CoursIA -- paths: translations/genai/finetuning.csv, MyIA.AI.Notebooks/GenAI/FineTuning/FT-02-QLoRA-Quantization-Python_en.ipynb, scripts/tests/baseline_nb_nav_chain.json, scripts/translation/tests/test_check_translation_parity.py, scripts/translation/tests/test_demo_t3_t4_acceptance.py
Grain: MED/notebook-python -- lane myia-po-2027:CoursIA -- prev: MED/refactor #19172
Tranche FineTuning suivante de #1650 (même contrat que #18966/#18968) : couverture EN complète de FT-02-QLoRA-Quantization — remplir les text_en manquants (17 MISSING_LANG mesurés par check_translation_sync.py sur origin/main à d0103b5), rafraîchir les 2 lignes SRC_DRIFT puis les traduire, rendre FT-02-...-Python_en.ipynb via T4 --require-translated, mettre à jour les trois fichiers de garde (baseline nav chain, EXPECTED_PAIR_COUNT, acceptance T3/T4). FT-04 (7 SRC_DRIFT, extraction md absente) reste pour la tranche suivante.
[BLOCKED] Tranche -Native / -Companion resorbes (series Lean) -- 6 PRs ouvertes touchent les memes chemins.
Le renommage est prepare et mesure, mais il ne peut pas partir maintenant : le garde de claim rend BLOCKED sur le scope, et pas pour un detail de bord.
Ce qui est pret.rename_notebooks.py --propose MyIA.AI.Notebooks/SymbolicAI/Lean rend 88 lignes : 46 RENOMMAGE, 20 A TRANCHER, 22 CONFORME. La sous-tranche « vocabulaire de noyau » (tout nom portant -Native ou -Companion en suffixe terminal) fait 17 carnets, tous resolus par le kernelspec :
-Native sous noyau Lean -> -Lean (dont deux doubles suffixes -Lean-Native qui perdent les deux) ;
-Companion terminal -> le suffixe de noyau du kernelspec (-Lean ou -Lean-Python).
Dry-run passe, aucune collision de cible. Le dry-run liste aussi 48 referents a reecrire, dont translations/symbolicai-lean/symbolicai-lean.csv (407 occurrences), _quarto.yml (48), README.md de la serie (85), docs/curriculum/ia-symbolique.md (45) et les baselines.
Pourquoi il ne part pas.check_lane_claim.py 1650 --paths ... rend BLOCKED : six PRs ouvertes d'autres lanes touchent ces chemins.
_quarto.yml, docs/curriculum/ia-symbolique.md, formal_logic_lean/**, Lean-03b-... -- et c'est elle-meme une tranche de suffixe de noyau (11 carnets + 47 referents)
_quarto.yml porte la navigation de toute la serie : tout renommage Lean le reecrit, donc aucune sous-tranche plus etroite n'echappe a la collision. Le dry-run montre les deux operations (la mienne et #19150) reecrivant la meme surface partagee -- les lancer en parallele fabriquerait exactement la collision cross-lane que le protocole de claim existe pour eviter.
Ce qui reste vrai et non bloque. La dette d'outil est prete et isolee : _canon de kernel_suffix_canon.json dit encore que « -Lean n'est PAS un suffixe de noyau (le pendant Lean porte -Native) », ce que l'arbitrage du 25/09 inverse. Verification faite : la docstring de check_kernel_suffix_canon.py est deja alignee (-Lean / -Lean-Python dans KERNEL_LANG_SUFFIXES, -Native en queue legacy) -- seule la ligne _canon du json est en retard. Sur ces deux chemins le claim rend CLEAR.
Ce qu'il faut pour repartir : que _quarto.yml cesse d'etre touche par une PR ouverte (les cinq ci-dessus mergent ou rebasent), puis la tranche se rejoue en une commande. Le plan et la table sont rejouables a l'identique (--propose puis --mapping).
[CLAIMED] lane myia-po-2025:CoursIA -- declaration du compte de paires de traduction (EXPECTED_PAIR_COUNT 8 -> 9), rouge de base sur main depuis #19996
Grain: MED/notebook-python -- lane myia-po-2023:CoursIA -- prev: DEEP/lean #20439
[CLAIMED] lane myia-po-2023:CoursIA -- paths: translations/genai/image.csv, MyIA.AI.Notebooks/GenAI/Image/01-Foundation/**, scripts/translation/tests/test_check_translation_parity.py, scripts/tests/baseline_nb_nav_chain.json -- tranche T3+T4 EN de la serie Image, sous-dossier 01-Foundation (carnets 01-1 a 01-5b, ~200 cellules md dans le CSV pivot) : remplissage text_en/hash_en + rendus _en + guards (EXPECTED_PAIR_COUNT, baseline nav chain). Suite de la sequence 4 de #1650, sous-grain de l'EPIC #4208 (tete de tapis c.1495, axe E debloque). Volume probablement coupe en 2-3 PR selon la fenetre.
[DELIVERED] lane myia-po-2023:CoursIA — PR1 du chantier (tranche Image 01-Foundation, carnets 01-1 + 01-2) livrée : PR #20449.
37 cellules md traduites EN (21 + 16), 2 rendus _en T4 --require-translated (0 fallback, 0 orphelin), guards à jour (EXPECTED_PAIR_COUNT 11, baseline nav chain +2 orphan_entry).
3 réparations motivées en commits séparés : id conclusion sur la cellule sans id de 01-2 (invisibilité T1/T4), lien nav manquant 01-5 → 01-5b (rupture préexistante révélée par le dé-wrapping de la série), filtre extracteur _<lang> (non-idempotence du refresh T1 : jusqu'à +67 lignes miroir).
Tranches suivantes identifiées : 01-3 / 01-4 / 01-5 / 01-5b (lignes déjà resynchronisées dans le CSV par le T1 refresh de cette PR).
Mandat utilisateur (verbatim)
— jsboige, 2026-05-28, à ai-01:CoursIA (low priority, troisième Epic dans la série Conway #1647 / Grothendieck #1646 / Traduction)
Décisions user du 2026-09-22 — architecture de distribution (remplacent les arbitrages des Phases 2, 3 et 4)
Discussion stratégique ai-01 ↔ user du 2026-09-22. Verbatims :
1. Un dépôt de distribution par langue — pas de siblings
xxx_<lang>.ipynb, pas de fork, pas de LFSMesure du 2026-09-22 : le dépôt pèse ~2,8 Go d'historique sur GitHub (104 forks) ; les 1 371 notebooks de l'arbre courant font 639 Mo (médiane 96 Ko, les 5 plus gros GenAI Audio/Image = 124 Mo). Sept langues cibles en siblings = +4,5 Go d'arbre courant dès la première vague, puis chaque ré-exécution multipliée par 8. GitHub recommande de rester sous 5 Go.
xxx_<lang>.ipynbdans CoursIAvalidate_pr_notebooks) aveugles ; contributeur sansgit-lfs= notebooks cassés ; bande passante facturée au propriétaire ; alléger l'existant exigerait de réécriremain(interdit). LFS reste pertinent pour de vrais binaires à venir (dll/exe/pt/pdf)CoursIA-en,CoursIA-es, …)translations/, texte) ; chaque dépôt de langue ≈ taille d'un instantané ; README natif, topics, site indexable dans sa langue2. Le code est traduit et exécuté dans chaque dépôt localisé
Remplace « le code lui-même n'est jamais traduit » (Phase 2) et « conserve
execution_countetoutputsdu source » (Phase 3). Chaque notebook localisé porte ses propres sorties d'exécution réelle (C.2 s'applique dans chaque dépôt de langue, comme ici). Conséquence de chantier : l'extracteur doit couvrir identifiants, chaînes affichées, commentaires et légendes, avec une garde qui vérifie que le code traduit s'exécute (la parité de comportement se mesure à l'exécution, pas au diff).3. PRs localisées acceptées — comparaison entre dépôts distincts
Une contribution peut arriver dans un dépôt de langue. L'organe de détection d'évolution (CSV par série de #4957,
scripts/translation/check_translation_sync.pyet ses 6 verdicts,multilingual_drift_audit.py) doit comparer entre dépôts, et non plus seulement à l'intérieur de CoursIA. Modèle à réutiliser plutôt que réinventer (organ-first) : la parité jumeaux Python/C# — registre de paires avec empreintes de contenu, attestation, audit de dérive (scripts/notebook_tools/check_twin_parity.py,twin-parity*.yml). Une paire devient(notebook FR @ sha, notebook <lang> @ sha, dépôt); une évolution d'un côté se propage vers l'autre par PR, dans les deux sens.4. Séquence
-Lean-Python(au moins 36 notebooks Python pilotent Lean, aucun suffixé), casse du suffixe C# (96-Csharpvs 34-CSharp), consolidation des lakes — la mémoire de traduction est indexée par chemin +cell_id, tout renommage postérieur casse les clés dans chaque langue.Insight pivot — un moteur unique, trois couches CoursIA
Le datasetupdater d'Argumentum existe déjà et tourne en production sur le jeu Argumentum. CoursIA ne réinvente rien : on connecte. Le travail réel se réduit à modeler le contenu pédagogique en CSV équivalent à un dataset Argumentum, puis à redéposer le résultat traduit dans la forme attendue (notebook ou markdown).
*.ipynbmarkdown cells + code commentsnotebook_path,cell_id,cell_type,paragraph_idx,text_fr,placeholders_jsonxxx_en.ipynb,xxx_es.ipynb, …README.md,docs/**/*.md,CLAUDE.mdmd_path,paragraph_id,heading_path,text_frREADME.en.md,docs/en/**.md, PPTXslide_id,text_fr,placementslides.en.md, …Dépendance bloquante — LEVÉE le 2026-06-09, remplacée par trois gates qui vivaient en commentaires
Ce que cette section disait jusqu'au 2026-09-01 : « #1271 doit être mergé avant Phase 1. État actuel (dashboard 2026-05-26) : GELÉ pending feu vert user post-PrCon. »
C'est faux depuis près de trois mois. #1271 est CLOSED le 2026-06-09, et le sous-module Argumentum est présent sur
mainàMyIA.AI.Notebooks/SymbolicAI/Argument_Analysis/Argumentum(git ls-tree origin/main, gitlink1c5231f6, vérifié le 2026-09-01). Le datasetupdater est atteignable. Une lane qui tirait cette EPIC lisait « GELÉ », concluait qu'elle était bloquée sur autrui, et la reposait — c'est le mécanisme de délaissement que #11900 décrit, et il a tourné ici pendant 84 jours.Les trois gates réels — ils existent, mais ils ne sont pas celui-là
Aucun ne bloque le moteur ; tous les trois bloquent la production de traductions. La distinction est ce qui rend cette EPIC de nouveau piochable.
on: pushdetranslation-sync.ymlest neutralisé par décision user du 2026-08-12 ; le moteur ne tourne plus que surworkflow_dispatch. Ce n'est pas une panne : c'est le hold qui empêche la production de repartir avant les gates 1 et 2.Ce qui est donc piochable aujourd'hui, sans lever aucun gate
Le moteur et son outillage sont largement construits, et rien n'interdit de les finir ou de les vérifier :
scripts/translation/porte 14 modules surmain— extraction (extract_cells_to_csv.py, 37 tests hermétiques test(translation,#4957): cover extract_cells_to_csv.py T1 — 37 tests, stdlib-only hermetic #9265), contrôle de dérive (check_translation_sync.py, 50 tests couvrant les 6 verdicts test(translation,#4957): cover check_translation_sync.py T2 — 50 tests, all 6 drift verdicts #9266), réinjection (translate_csv.py, 22 tests round-trip test(translation,#6949): round-trip fixture-first tests for T3 fork translate_csv.py (22 tests) #7023), plus parité, périmètre, spans de code inline, audit de dérive multilingue.translations/porte ~20 séries en CSV, resynchronisées à plusieurs reprises (chore(translation,#4957): resync GenAI/Texte CSV drift (24 SRC_DRIFT -> 0) #6951, chore(translation,#4957): resync Search/Applications CSV drift (3 SRC_DRIFT -> 0) #7098, chore(translation,#4957): resync symbolicai-lean CSV drift (1 SRC_DRIFT -> 0) #7235, fix(translation,#4957): resync translations/probas-pymc/probas_pymc.csv (262 SRC_DRIFT → 0) #7695).translation_golden_set.jsonn'existe pas (finddu 2026-09-01) — c'est le seul sous-critère de la Phase 0.5 qui n'est pas livré, et il est petit : indexer les paires FR/EN déjà produites par le défrichage manuel. C'est le grain le plus immédiat de cette EPIC, et il pré-remplit l'étalonnage de la Phase 4.Les phases ci-dessous conservent leur rédaction d'origine ; leur état réel est celui du tableau ajouté en tête de la section « Phases ».
État des phases au 2026-09-01 (ai-01) — le plan ci-dessous n'avait jamais été coché
translation_golden_set.jsonabsentmaindepuis #1271 (CLOSED 2026-06-09)extract_cells_to_csv.py+ 37 tests (#9265) ; ~20 séries danstranslations/translate_csv.py+ 22 tests round-trip (#7023)check_translation_sync.py+ 50 tests, 6 verdicts (#9266) ;multilingual_drift_audit.pyLe plan d'origine séquençait tout derrière « #1271 puis le moteur ». Le plateau a fait l'inverse : le moteur est construit, c'est la production qui est tenue — délibérément, par des décisions user. Lire les phases dans l'ordre du plan induit en erreur ; lire ce tableau ne le fait pas.
Phases
Phase 0 — Prérequis & inventaire (1-2h, hors blocage)
find MyIA.AI.Notebooks -name "*.ipynb" -not -name "*_output.ipynb" -not -name "*_<lang>.ipynb"(1 181 notebooks source surorigin/mainau 2026-08-30 — l'estimation initiale « ~400 » était fausse d'un facteur ~3 ; le README du 17/08 annonçait déjà 1 024)find . -name "*.md" -not -path "./node_modules/*" -not -path "./.git/*"(READMEs + docs)find MyIA.AI.Notebooks -name "slides.md" -o -name "slides_*.md"Phase 0.5 — Défrichage manuel ad-hoc EN→FR (4-8h, déblocable maintenant, sans Argumentum)
Rationale (pourquoi avant la Phase 1 scriptée).
git mv/Write.*.en.md. La manœuvre récupère l'original EN comme<doc>.en.mdau passage — exactement le livrable que la Phase 3 scriptée générerait automatiquement plus tard. Le défrichage manuel pré-remplit donc le périmètre EN.Convention naming. Alignement sur l'Epic existant (Phase 3) :
README.en.md,<name>.en.md(séparateur point, standard i18n, cohérent avecxxx_<lang>.ipynb). Note : le mandat user écritReadme_en.md(underscore) ; on standardise surREADME.en.mdpour cohérence avec la Phase 3 déjà documentée — à confirmer par le user si l'underscore est préférable.Périmètre issu du scan 2026-06-12 (docs EN-dominants, ratio stop-words EN/FR > 0.60, >100 mots), filtré pour ne garder que les docs CoursIA pérennes :
QuantConnect/projects/{DualMomentum,PairsTrading,TrendFilteredMeanReversion,composite-c1-multiasset,composite-c2-equityfactor,Mamba-Crypto-Ranking,ML-Classification,Research-Executor,Framework_Composite_FamaFrenchAllWeather}/README.md(≈10 fichiers, ~120-380 mots chacun)Probas/PORT_PYTHON_PLAN.md(718w),Probas/Infer/scripts/README.md,QuantConnect/datasets/yfinance/crypto_panier/README.md,QuantConnect/partner-course-quant-trading/templates/student-presentation/README.mdGameTheory/cooperative_games_lean/README.md,GameTheory/social_choice_lean_peters/README.md,SymbolicAI/Lean/sensitivity_lean/NOTICE.mdscripts/qc-mcp-lite/README.md,scripts/datasets/README.md,docker-configurations/notebook-runner/README.md,docs/reference/claude-code-config.md(300w)Exclus du défrichage (tri pérenne vs éphémère) :
*AUDIT*.md,qc_projects_audit_*.md,audit_consolidation_qc.md,M10_DM_RETROACTIF.md,verdict.md,quantbooks_execution_status.md,STABLE_SNAPSHOT*.md) → relèvent du nettoyage dashboard (cf harness-hygiene), pas de traduction..claude/rules/,.claude/skills/,.claude/agent-memory/,CLAUDE.md) → déjà hors scope déclaré (lecteur unique = agents francophones)..lake/packages/{mathlib,Cli,importGraph}/) → dépendances tierces, jamais traduire.docs/archive/*) → déjà déplacés, pas prioritaires..claude/worktrees/**) → copies temporaires, ignorer (doublons du repo principal).Processus ad-hoc par doc (manuel, non scripté) :
<doc>.md→<doc>.en.md(contenu anglais préservé verbatim). Pour unREADME.md:README.md→README.en.md.<doc>.mden français (traduction humaine assistée) — devient la source FR primaire.translation_golden_set.json(source FR + source EN + chemin) pour réutilisation Phase 4.Phase 1 — Connecteur Argumentum → CoursIA (4-6h)
scripts/translation/argumentum_bridge.py:translate_csv(input_csv_fr, target_langs) -> dict[lang, output_csv]Phase 2 — Extracteur CSV (8-12h)
scripts/translation/notebook_to_csv.py:.ipynb, parcourt lescells$...$et$$...$$(placeholders__LATEX_0__, etc.)`(placeholders)#///(les strings restent en français quand elles font partie de la pédagogie ; le code lui-même n'est jamais traduit)cell_idpour réinjection ordonnéescripts/translation/markdown_to_csv.py:.md, segmente par paragrapheheading_pathau lieu decell_idPhase 3 — Réinjecteur (8-12h)
scripts/translation/csv_to_notebook.py:(notebook_fr_source, csv_translated, target_lang)xxx_<lang>.ipynbà partir du source FR, en remplaçant les textes français par leurs traductionsexecution_countetoutputsdu source (cf règle C.2 — pas de re-exécution automatique des notebooks traduits)<basename>_<lang>.ipynbscripts/translation/csv_to_markdown.py:README.en.md,docs/architecture.en.md, etc.Phase 4 — Pilote sur 1 série (6-8h)
Choisir une série compacte avec markdown riche. Candidats :
MyIA.AI.Notebooks/IIT/(PyPhi, 4-6 notebooks, contenu théorique dense)MyIA.AI.Notebooks/Probas/(Infer.NET, markdown abondant)MyIA.AI.Notebooks/SymbolicAI/Lean/Lean-1 à Lean-3 (introduction Lean, audience internationale forte)Pipeline complet sur la série pilote dans 2 langues (EN + ES). Validation manuelle de la qualité, ajustements du pipeline.
Arbitrages décidés en Phase 4 :
xxx_<lang>.ipynbà côté du source vs répertoires séparésnotebooks/<lang>/xxx.ipynbPhase 5 — Scale-up batch (16-24h walltime)
Driver
scripts/translation/translate_repository.py:translation_manifest.jsonavec entrées :source_path,target_lang,sha256_source,timestamp,argumentum_version,statusPhase 6 — Drift detection & maintenance (6-10h)
Quand un notebook FR source change, comment savoir quelles traductions retraduire ?
translation_manifest.jsonconservesha256_sourceau moment de la traductionscripts/translation/check_drift.py:(source, lang)à retraduire--auto-retranslatepour batchPhase 7 — Index langues & navigation (4-6h)
index.en.md,index.es.md, … pointant vers les README de série traduitsREADME.md(FR) +README.<lang>.mdPhase 8+ (hors scope initial)
Stratégie "fichiers précieux mis en avant" — Argumentum
Le datasetupdater Argumentum est un outil utilisateur (jsboige) précieux. Il doit être :
Cité publiquement dans le README racine CoursIA :
Crédité dans le docstring de
argumentum_bridge.py:Importé verbatim : pas d'altération du datasetupdater côté CoursIA. Toute adaptation va dans le bridge, jamais dans le sous-module.
Documenté dans une page dédiée
docs/translation-engine.md:Hall of Fame
Set confirmé Argumentum Data-Gate v0.9.0 (relevé dashboard Argumentum workspace 2026-05-28) : EN, FR, ES, AR, FA, ZH, RU, PT (8 langues, 4 datasets matures : Rules / Virtues / Scenarii / Fallacies). Backend gpt-5.5, garde-fou ~$8/PR, plafond ~$120/Phase. Si Argumentum v1.0 ajoute DE / IT / JA, CoursIA suit en cycle suivant — la matrice Argumentum reste la source de vérité.
Estimation
*.en.md+ golden setRisques & mitigation
#///; jamais les strings code ; tests sur 10 notebooks code-intensive avant scale-up__LATEX_N__réinsérés post-traductiondocs/<lang>/,notebooks/<lang>/si la pollution racine devient problématiquetranslation_manifest.json+ check_drift.py + hook optionnelMyIA.AI.Notebooks/source (pasjsboige*/*forks étudiants)Critères de complétion
<doc>.en.md;translation_golden_set.jsonconstituédocs/translation-engine.md)Hors scope (initial)
Voir aussi
feedback-community-witnesses-credited(paternité du datasetupdater),feedback-mandate-amplification("pharaonique mais réutilisation cleane" = scope assumé)🤖 Generated with Claude Code pour ai-01:CoursIA cycle 92, suite mandat user 2026-05-28.
Corrections vérifiées (2026-08-30 — tri ROO-1, réfutations Vibe)
origin/main(SHA68e7a663, git treestruncated:false, exclusions_output/_<lang>), cohérent avec le README (« 1 024 notebooks » au 17/08) et l'audit Vibe (1 011 le 29/08). Toute projection de coût/temps doit se recalculer sur ~1 200, pas 400.translations/(33 CSV, 804 notebooks couverts selon l'audit) utilise déjànotebook,cell_id,cell_type,src_lang,src_hash,text_fr,text_en,text_es,text_ar,text_fa,text_zh,text_ru,text_pt,hash_*,translate_policy— vérifié surtranslations/genai/audio.csv(origin/main). Le schéma proposé dans cette issue (notebook_path,paragraph_idx,placeholders_json) n'existe nulle part dans le corpus et ignorerait 7 colonnes de langues + les colonneshash_*de détection de changement. Toute implémentation doit partir du schéma existant.