Le personnage de coton souriant du logo original de Cotton, sans fond ni lettrage
Retour à la salle

Cotton

Translation workflow

Des traductions générées aux résultats révisables.

Un workflow de traduction pour les dialogues de jeux vidéo.

2026.05.06 — 2026.05.26

Projet professionnel · traitement des traductions, jugement et chemin de revue

  • Application webImplémenté · développement

Cotton vocabulary

Lens
Refinement Loop
Translation
Quality Estimation
Workflow
Job Control
Human Review
  1. prompt layers
  2. glossary
  3. generation
  4. revision
  1. judge
  2. hard gate
  3. score
  1. intake
  2. checkpoint
  3. spend control
  4. stale sweep
  1. approval
  2. correction
  3. audit trail

Prompt Layers: SYSTEM_PROMPT_L0 · buildTranslateUserMessage · L1 CONTRACT · L3 SPEAKER · L6 SOURCE · L7 INSTRUCTION · ICU PLACEHOLDER · INLINE TAG · TARGET TEXT ONLY · FORCED MAPPING · L2 GLOSSARY · speaker_keyGlossary: glossary_term · fetchGlossaryHits · canonical_form · forbidden_translations · SUBSTRING MATCH · FORCED MAPPING · FORBIDDEN ALTERNATIVE · L2 GLOSSARY · glossary_hits · glossary_complianceGeneration: AdapterRegistry · anthropic-sdk · openai-sdk · claude-local · codex-local · llm_plan · PIVOT_VIA · shouldPivot · COTTON_ADAPTER_CONCURRENCY · NODE_OPTIONS · pivot_register_carry · translation.refinedRevision: buildTranslateUserMessage · L7 INSTRUCTION · runRefinementLoop · priorAttempt · priorCritique · REJECTED BY THE JUDGE · maxTurns · willRetry · RefinementHooks · HOOK ABORT · turn_count_to_final · critique_for_retry · failingDimensions · cost_ceiling_usd · needs_reviewJudge: glossary_hits · runJudge · JUDGE_SYSTEM_PROMPT · judgeModel · TEMPERATURE 0 · parseJudgeResponse · FOUR-SECTION XML · VERBATIM CHUNKS · severity · critique_for_retry · judge_citation · missingHardGates · TRIGGER ABSENT = PASS · judge.scoredHard Gate: ICU PLACEHOLDER · INLINE TAG · FORBIDDEN ALTERNATIVE · hard_gate_fail · hardGatePassed · glossary_compliance · cps_budget_compliant · icu_validity · inline_tag_preserved · length_constraint · HARD GATE FIRST · missingHardGates · TRIGGER ABSENT = PASSScore: HARD GATE FIRST · computeVerdict · cottonEvalScore · WEIGHTED AVERAGE · tone_register · personality_consistent · emotional_state_match · cultural_marker_preserved · accuracy · pivot_register_carry · auto_approve_threshold · failingDimensions · approval_gate · judge.scoredIntake: processXlsxBytes · classifySheetName · parseGoogleSheetsUrl · source_file · content_sha256 · extractStageDirection · speaker_key · ingest_session · segment.ingested · github.push.receivedCheckpoint: translation_progress · last_completed_step · turn_translated · turn_judged · finalized · jobEntryGuard · SELECT FOR UPDATE · attempt_count · DEFAULT_MAX_RESUME_ATTEMPTS · TWO-TX SPLIT · ON CONFLICT DO NOTHINGSpend Control: llm_plan · costCap · cost_ceiling_usd · rateLimit · FailoverDispatcher · haltOnQuota · detectQuotaFromStream · quota_daily_exhausted · auth_revoked · NO AUTO-SWAP · needs_credential · POST /:id/resumeStale Sweep: COTTON_ADAPTER_CONCURRENCY · NODE_OPTIONS · attempt_count · runStaleSweep · STALE_THRESHOLD_INTERVAL · DLQ_ATTEMPT_CAP · LIMIT 200 · re_enqueued · dead_lettered · ORPHAN RE-ENQUEUE · IN-FLIGHT SET · /health/queues · maxStalledCount · needs_reviewApproval: auto_approve_threshold · ingest_session · SELECT FOR UPDATE · needs_credential · POST /:id/resume · POST /:id/approve · POST /:id/unapprove · POST /:id/reject · APPROVE_FROM · REJECT_FROM · needs_review · reviewer_id · HITL · approval_gate · translation.approved · EDIT & APPROVE · actor_idCorrection: POST /:id/correct · corrected_text · CORRECT_FROM · EDIT & APPROVE · human_corrected_segments · human-corrected-after-mt · translation.human_corrected · supersedes · NEW REVISION · IMMUTABLE HISTORYAudit Trail: turn_count_to_final · severity · judge_citation · content_sha256 · segment.ingested · github.push.received · translation.approved · human_corrected_segments · translation.human_corrected · IMMUTABLE HISTORY · event_log · appendNextEvent · ULID · AGGREGATE VERSION · translation_state_log · actor_id · llm_call_log · telemetryHook · judge.scored · translation.refined

Scores, nouvelles tentatives et revue humaine, chacun à sa frontière.

Génération et jugement partagent le glossaire, et l’échec d’une hard gate rapporté par le modèle juge ne peut pas être compensé par le score moyen. Les états intermédiaires de traduction et de jugement sont consignés, les limites de tentatives et de coût sont distinguées des identifiants épuisés, et les jobs bloqués retournent à la file ou à la revue selon la cause.

Ce projet professionnel relie dans un même flux la génération de traductions, le jugement de qualité rapporté par le modèle, les nouvelles tentatives et la revue humaine.

Du début du dépôt au travail confirmé pendant la mission

Une application web composée d’écrans d’édition et d’approbation des traductions, d’une API et d’un worker de jobs, qui tourne dans l’environnement de développement.

Carte du flux de jugement · d’après des enregistrements d’implémentation privés
Cotton : jugement des traductions · nouvelle tentative · repriseL’API enregistre le texte source et les locales cibles en base de données, puis met en file un job par locale cible. Un worker verrouille la ligne, vérifie la tentative, crée le brouillon et l’état d’avancement, génère une traduction avec le glossaire, puis appelle séparément un modèle juge avec le même glossaire. La traduction (Tx1) et le jugement avec ses preuves (Tx2) sont consignés dans des transactions distinctes. Le code agrège le jugement pour que l’échec d’une hard gate ne soit pas compensé par la moyenne : un succès est finalisé, un échec obtient un nouveau tour, la limite de tours ou de coût l’envoie en revue humaine, et un signal de quota ou d’authentification arrête les dépenses et attend un contrôle des identifiants. Un balayage des inactifs examine jusqu’à 200 brouillons de plus de 10 minutes : celui à qui il reste des tentatives mais absent de la file est remis en file, et celui qui a épuisé ses tentatives va en revue ou au contrôle des identifiants selon qu’un résultat existe.Source · locales ciblesSegments stockésRevue humaineneeds_review · pas une approbationContrôle des identifiantsneeds_credentialAPI · enregistrement des jobsMise en file après commitFile de jobsBullMQ · ID de jobEntrée du jobVerrou de ligne · vérification de la tentativeGlossaire · contexteGlossaire de l’espace de travailTour de traductionGénérer · appel au modèleAppel au modèle juge · analyseRègles de verdictHard gate · moyenne pondéréeNouvelle tentative · dépensesTours · coût · quotaÉtat de la traductionBrouillon · avancementLignes de traduction · de jugementÉtat · journal des appelsFinalisationTransaction finaleContrôle de la fileComparer l’état de la fileBalayage des inactifsBrouillons de plus de 10 min · max 200Entrée · fileGénération · jugementÉtat · acceptationReprise · décision humaine1source2 après commit · Mise en file après commit → BullMQ · ID de job23 transmettre le job · BullMQ · ID de job → Verrou de ligne · vérification de la tentative34ligne d’avancement5tentative autorisée1glossaire2 même glossaire · Glossaire de l’espace de travail → Appel au modèle juge · analyse23Tx1 · traduction4Tx2 · jugement5 scores · gates · Appel au modèle juge · analyse → Hard gate · moyenne pondérée56verdict7pass8enregistrement final1verdict2tour suivant3limite · abandon4quota · authentification5reprise manuelle1brouillon inactif2 sous la limite · Brouillons de plus de 10 min · max 200 → Comparer l’état de la file23remise en file4 résultat présent · Brouillons de plus de 10 min · max 200 → Revue humaine45aucun résultat

Enregistrement → entrée

Mis en file après le commit en base ; un worker verrouille la ligne, vérifie la tentative et crée le brouillon.

  1. Source · locales ciblesDonnées: sourceMise en file après commitAPI · enregistrement des jobs

    Les segments source et les locales cibles du projet sont stockés en base de données. Les données clients ne sont pas montrées.

  2. Mise en file après commitAPI · enregistrement des jobsDonnées: après commitBullMQ · ID de jobFile de jobs

    Après le commit en base, un job avec un ID propre à la requête est mis en file pour chaque locale cible active. Si la mise en file échoue, seul un avertissement est journalisé et le commit n’est pas annulé (pas d’outbox atomique) ; c’est pourquoi le balayage des inactifs existe.

  3. BullMQ · ID de jobFile de jobsExécution · jugement: transmettre le jobVerrou de ligne · vérification de la tentativeEntrée du job

    BullMQ transmet le job à un worker de façon asynchrone.

  4. Verrou de ligne · vérification de la tentativeEntrée du jobDonnées: ligne d’avancementBrouillon · avancementÉtat de la traduction

    Dans une transaction, la ligne d’avancement est verrouillée et une traduction brouillon est créée. Les nouvelles tentatives automatiques des jobs finalisés ou suspendus pour identifiants sont ignorées ; les demandes manuelles sont traitées à part.

  5. Verrou de ligne · vérification de la tentativeEntrée du jobExécution · jugement: tentative autoriséeGénérer · appel au modèleTour de traduction

    Le compteur de tentatives augmente d’un dans sa limite, puis le tour de traduction commence.

Générer → juger → finaliser

Génération et jugement utilisent le même glossaire ; la traduction et le jugement sont consignés séparément, et le code agrège le jugement avant de finaliser.

  1. Glossaire de l’espace de travailGlossaire · contexteDonnées: glossaireGénérer · appel au modèleTour de traduction

    Le glossaire et le contexte de l’espace de travail sont recherchés et transmis à la génération.

  2. Glossaire de l’espace de travailGlossaire · contexteDonnées: même glossaireAppel au modèle juge · analyseTour de traduction

    Le jugement reçoit les mêmes contraintes de glossaire.

  3. Générer · appel au modèleTour de traductionDonnées: Tx1 · traductionLignes de traduction · de jugementÉtat de la traduction

    Le modèle est appelé directement ou via un pivot en-US, et l’appel, l’événement et l’avancement sont écrits dans une seule transaction. Si le job est relancé après un crash, l’appel de traduction et son coût peuvent se répéter.

  4. Appel au modèle juge · analyseTour de traductionDonnées: Tx2 · jugementLignes de traduction · de jugementÉtat de la traduction

    Les scores et les preuves du juge sont insérés une fois par traduction et par tour ; un doublon retrouve la ligne existante, et les citations ne sont écrites qu’à la première insertion. Ce n’est pas la même transaction que la traduction.

  5. Appel au modèle juge · analyseTour de traductionDonnées: scores · gatesHard gate · moyenne pondéréeRègles de verdict

    La réponse du modèle juge est analysée en scores par dimension et en résultats de gates. Le passage du glossaire est ce que rapporte le modèle juge.

  6. Hard gate · moyenne pondéréeRègles de verdictExécution · jugement: verdictTours · coût · quotaNouvelle tentative · dépenses

    Tout échec de hard gate rapporté donne un zéro et un échec ; ce n’est qu’ensuite que s’appliquent la moyenne pondérée et les seuils par dimension. Le seuil global de 8.0 est une valeur de configuration par défaut, pas une qualité de traduction observée.

  7. Tours · coût · quotaNouvelle tentative · dépensesExécution · jugement: passTransaction finaleFinalisation

    Un succès est finalisé comme translated.

  8. Transaction finaleFinalisationDonnées: enregistrement finalÉtat · journal des appelsÉtat de la traduction

    Candidat, état, score et tours sont finalisés, et l’avancement finalized et le journal d’état sont écrits dans une seule transaction. Un événement de traduction terminée n’est émis que pour translated.

Nouvelles tentatives · limites de dépenses

Pas de succès : un nouveau tour ; une limite : la revue humaine ; quota ou authentification : arrêt des dépenses en attendant la reprise par un opérateur.

  1. Hard gate · moyenne pondéréeRègles de verdictExécution · jugement: verdictTours · coût · quotaNouvelle tentative · dépenses

    Tout échec de hard gate rapporté donne un zéro et un échec ; ce n’est qu’ensuite que s’appliquent la moyenne pondérée et les seuils par dimension. Le seuil global de 8.0 est une valeur de configuration par défaut, pas une qualité de traduction observée.

  2. Tours · coût · quotaNouvelle tentative · dépensesExécution · jugement: tour suivantGénérer · appel au modèleTour de traduction

    Une traduction qui ne passe pas est générée à nouveau avec la traduction précédente et la critique. Même un échec de hard gate peut d’abord être retenté au lieu d’aller directement à une personne.

  3. Tours · coût · quotaNouvelle tentative · dépensesExécution · jugement: limite · abandonRevue humaine

    Quand les tours sont épuisés ou que le plafond de coût est atteint, le job est finalisé comme needs_review. Finalisé signifie que le traitement est terminé, pas qu’une personne l’a approuvé.

  4. Tours · coût · quotaNouvelle tentative · dépensesÉchec · limite: quota · authentificationContrôle des identifiants

    Un signal de quota ou d’authentification arrête les dépenses et pose needs_credential. Il n’y a pas de bascule automatique vers un autre compte ou fournisseur. Les erreurs de transport sans signal d’arrêt repartent vers les nouvelles tentatives de BullMQ.

  5. Contrôle des identifiantsExécution · jugement: reprise manuelleBullMQ · ID de jobFile de jobs

    Un opérateur qui a vérifié les identifiants relance explicitement.

Reprise des jobs inactifs

Les vieux brouillons sont triés par cause : absent de la file, remise en file ; tentatives épuisées, décision humaine.

  1. Brouillon · avancementÉtat de la traductionObservation · rapport: brouillon inactifBrouillons de plus de 10 min · max 200Balayage des inactifs

    Jusqu’à 200 candidats restés brouillons plus de 10 minutes sont lus, les plus anciens d’abord. La requête ne prend aucun verrou et les mises à jour et journaux sont des instructions séparées ; ce n’est donc pas décrit comme un lot sans course.

  2. Brouillons de plus de 10 min · max 200Balayage des inactifsExécution · jugement: sous la limiteComparer l’état de la fileContrôle de la file

    Avec moins de tentatives que la limite (3), le job est comparé aux états de file active, waiting, delayed et prioritized. Dans le code, la branche des tentatives épuisées précède ce contrôle de la file.

  3. Comparer l’état de la fileContrôle de la fileExécution · jugement: remise en fileBullMQ · ID de jobFile de jobs

    Si le job n’est pas dans la file, il y est remis. L’API utilise des ID avec un suffixe de requête alors que le balayage cherche l’ID de segment et de locale ; ce n’est donc pas décrit comme couvrant toutes les requêtes en cours.

  4. Brouillons de plus de 10 min · max 200Balayage des inactifsExécution · jugement: résultat présentRevue humaine

    Avec les 3 tentatives utilisées et un résultat de traduction présent, le job passe à needs_review.

  5. Brouillons de plus de 10 min · max 200Balayage des inactifsExécution · jugement: aucun résultatContrôle des identifiants

    Avec les 3 tentatives utilisées et aucun résultat, le job passe à needs_credential.

Toutes les connexions avec la même épaisseur. Choisissez un flux pour ne mettre en évidence que son chemin, avec des étapes numérotées.

  • Trait plein · sens des entrées, résultats et enregistrements
  • Tirets · exécution, jugement, requête
  • Pointillés longs · observation et rapport, hors jugement
  • Tirets courts · échec, arrêt, limite
  • Trait noir épais · le flux sélectionné ; les numéros donnent l’ordre
  • Cadre · frontière de code ou d’état, nommée dans l’en-tête
  • Pastille intérieure · composant de cette frontière
  • Cadre pointillé · hors de cette frontière
  • Contour orange · là où un modèle décide
  • Génération · dépenses · finalisation
  • Entrée · règles de verdict · balayage
  • File · état · enregistrements
  • Enregistrement · contrôle de la file

Tracé d’après des enregistrements privés d’implémentation et de développement. Les données clients et les chemins de code ne sont pas montrés.

Un balayage
May 26, 2026, un cycle de balayage dans l’environnement de développement : 200 contrôlés, 106 transitions d’état, 2 remis en file. Une transition d’état n’est pas une traduction réussie, et la répartition des 106 par état de destination n’est pas consignée.
Pourquoi pas exactement une fois
Les enregistrements sont écrits sans doublons, mais si un job est relancé après un crash, les appels au modèle et leur coût peuvent se répéter. La limite de concurrence est par processus, pas à l’échelle du cluster.
Portée du verdict
Empêcher une moyenne de masquer un échec de glossaire est une règle d’agrégation sur les gates rapportées. Cela ne prouve pas que chaque terme interdit est trouvé ni que la qualité est celle d’un natif.