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.csv

Exclut _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_ matchent les notebooks courants
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/ --check

En 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).

Voir aussi

  • Issue #4957 — design de l’infrastructure (schéma, sémantique drift, séquencement T0→T3)
  • Epic #1650 — traduction multilingue du dépôt
Retour au sommet