Scripts de synchro traduction (Epic #4957 / #1650)
Infrastructure de synchronisation multilingue pour les notebooks pédagogiques. Trois couches : T1/T2 (alignement — maintiennent le CSV source de vérité fr et détectent le drift) + T3 (translate_csv.py, fork Argumentum translate_game_rules.py, moteur de traduction gated). Mapping complet Argumentum → CoursIA : docs/translation/argumentum-fork-mapping.md.
Workflow en 3 couches (T1 → T2 → T3)
| Couche | Script | Rôle | Statut |
|---|---|---|---|
| T1 | extract_cells_to_csv.py |
Extrait les cellules des notebooks vers le CSV (langue pivot fr) |
Livré |
| T2 | check_translation_sync.py |
Détecte le drift (source modifiée / trad éditée / cellule supprimée) | Livré (non-bloquant, CI) |
| T3 | translate_csv.py |
Traduit les cellules text_fr vers les 7 langues cibles (text_<lang> + hash_<lang>) |
Moteur livré (#6976) + activation env-controlled (grain D #10043, umbrella #10038) : gate TRANSLATE_ENABLED (off par défaut) + --dry-run défaut + cap --max-cells. Premier --apply réel = mandat user (clé API env, #6949) |
Issue #6949 — Status de clôture (2026-07-22, c.757)
Issue #6949 — fork Argumentum vers CoursIA (T1/T2 + T3 gated) — CLOSED (livrable court-terme expédié).
Les deux PRs annoncées dans le scope de l’issue (#6949 § « 2 PRs ») sont MERGED sur main :
| PR | Commit merge | Livrable |
|---|---|---|
| #6976 | 84ba7ac70 |
scripts/translation/translate_csv.py — moteur T3 fork Argumentum, 14 tests, ENABLED=False + --dry-run (double garde, activation après GO user) |
| #6980 | fb9bff827 |
docs/translation/argumentum-fork-mapping.md + README T3 status — justification fork vs laisser, mapping schéma Argumentum → CoursIA, lessons gpt-5.5 |
Travaux d’harmonisation shipped post-issue (PRs additionnelles non-comptées dans le scope original mais traçables à #6949) :
- #7615 — provider-keys test env-hermetic (secrets hygiene, leçon pool args).
- #7714 — verdict
WRONG_SCRIPT(5e classe Argumentum alignée, c.734). - #7731 — verdict
FR_CONTAM(4e classe Argumentum alignée, c.738).
Hors-scope explicite (gated) : - Activation T3 — le mécanisme (gate TRANSLATE_ENABLED env, cap --max-cells, dégradation propre, cache src_hash) est livré par le grain D #10043 de l’umbrella #10038 ; le moteur reste gated (off par défaut). Le premier run --apply réel = mandat user (clé OPENAI_API_KEY env + GO), déclencheur Phase 1 de l’épic #1650 : la pre-flight account (coût API prod, choix LLM prod, stratégie de quota) sort du périmètre d’une PR de code. - T4 — re-import CSV → notebooks traduits (papermill --language <lang>) — travail post-activation, dépendant du retour d’expérience du premier run T3 réel.
Cible de revue cross-doc (à matérialiser au merge de la PR de clôture c.757) : docs/translation/argumentum-fork-mapping.md porte la même déclaration de clôture.
Schéma CSV (ratified #4957 §1)
translations/<famille>/<série>.csv — une ligne par cellule de notebook :
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_fr, hash_en, hash_es, hash_ar, hash_fa, hash_zh, hash_ru, hash_pt
cell_id= id nbformat stable (cellules sans id sont ignorées)src_hash= sha256(16) du texte normalisé (rstrip/ligne + strip newline terminal → pas de faux-drift cosmétique)- Colonnes pivot (
fr) remplies à l’extraction T1 ; colonnes cibles remplies par le moteur Argumentum en T3 - Le couple
(src_hash, hash_<lang>)détecte le drift dans les deux sens
extract_cells_to_csv.py (T1)
# Extraire le CSV initial d'une série (langue pivot fr, #1650 Phase 0.5)
python scripts/translation/extract_cells_to_csv.py MyIA.AI.Notebooks/SymbolicAI/Argument_Analysis/ \
-o translations/symbolicai/argument_analysis.csv
# Un seul notebook (POC / review du schéma)
python scripts/translation/extract_cells_to_csv.py notebook.ipynb -o poc.csvExclut _output.ipynb (sorties Papermill) et _agent.ipynb (auto-générées). Déterministe (re-extract byte-identique).
check_translation_sync.py (T2)
Détecte le drift entre les notebooks courants et le CSV. Non-bloquant (mode CI --check : exit 0 même si drift ; le rapport va sur stderr + JSON stdout). Verdicts :
| Verdict | Sens |
|---|---|
IN_SYNC |
src_hash et hash_ |
SRC_DRIFT |
le notebook source a bougé depuis la dernière synchro → retraduction requise |
TRAD_DRIFT |
une traduction a été éditée à la main sans repercussion sur le CSV |
MISSING_LANG |
le notebook xxx_<lang>.ipynb n’existe plus alors qu’un hash était déposé |
ORPHAN_ROW |
la ligne CSV référence un cell_id absent du notebook source (cellule supprimée) |
FR_CONTAM |
la traduction xxx_<lang>.ipynb est identique au source fr (non traduite, français leaké) — Argumentum 5-classes (4e), garde len>=4 (#6949) |
# Vérifier un CSV (exit 1 si drift)
python scripts/translation/check_translation_sync.py translations/symbolicai/argument_analysis.csv
# Vérifier tous les CSV (mode CI non-bloquant, exit 0)
python scripts/translation/check_translation_sync.py translations/ --checkEn phase POC (T1, seule la colonne pivot est remplie), le script ne remonte que du SRC_DRIFT éventuel ; l’absence de traductions déposées n’est pas un drift (c’est l’état attendu pré-T3). Le pivot (fr) étant le notebook source lui-même, sa cohérence est couverte par SRC_DRIFT — pas de faux MISSING_LANG sur le pivot.
Advisory resync-only (scripts/translation/check_resync_only.py, #6949 second half) : un PR qui ne touche QUE translations/**/*.csv ET n’ajoute aucun contenu text_<lang>/hash_<lang> (lang ∈ {en,es,ar,fa,zh,ru,pt}) est signalé ::notice non-bloquant (cf ruling coordinateur 2026-07-28 — « plus de PR resync-only jusqu’au GO moteur »). Le pivot text_fr/hash_fr reste autorisé (but légitime du resync).
Harmonisation taxonomie Argumentum (#6949) : ce script couvre désormais 4 des 5 classes de drift du fork multilingual-drift-audit.py — MISSING/ORPHAN (MISSING_LANG/ORPHAN_ROW), WRONG_SCRIPT (script Unicode attendu absent, c.734 #7714), FR_CONTAM (c.738). La 5e classe COGNATE (noms propres / faux-amis légitimement répétés, kind == "name", informationnelle — hors total_drift dans le fork) est N/A par construction : notre modèle est cell-based (pas de distinction name/prose).
CI
Le workflow .github/workflows/translation-drift.yml tourne sur les PR touchant les notebooks ou translations/ : il exécute check_translation_sync.py --check et surface le drift sous forme d’annotation notice (non-bloquant, read-only — même philosophie que catalog-drift.yml). La resync elle-même (T3) n’est JAMAIS auto-commitée en CI : elle est proposée par la détection et exécutée manuellement par un agent (moteur Argumentum, #4957 §3).