Journal des modifications
Les évolutions notables de Libris sont consignées ici. Libris suit le versionnage sémantique ; tant que le projet reste sous la version 1.0, une version mineure peut contenir des changements d’exploitation incompatibles, toujours signalés explicitement.
Cette version française couvre Libris 0.8.0 et les versions suivantes. Le journal anglais reste la référence : il contient l’historique complet, versions antérieures à la 0.8.0 comprises.
[Non publié]
[0.28.0] - 2026-10-05
Notes de mise à jour
- Une migration de base de données (
8e2f4a6c1d93) : la clé de mémoire de traduction des passages contenant des vers est recalculée. Rien d’autre ne change ; les autres clés sont identiques.
Modifié
- L’onglet Qualité du livre a un bouton Afficher les traitées : il charge les alertes déjà traitées (
history=true), chacune avec son badge « Traité », et Masquer les traitées revient aux alertes ouvertes. Les alertes traitées n’étaient plus affichées depuis que la liste ne renvoyait que les ouvertes. Closes #378. - La fiche de style présente désormais
guillemetscomme les « guillemets de la langue cible » ; le guide utilisateur français ne les décrit plus comme français. - Un terme verrouillé du glossaire qu’aucune réponse ne satisfait ne coûte plus au livre ses corrections ni son export. Les corrections d’un texte déjà traduit (arbitrage, proposition acceptée, révision après relecture, polissage, et leur réparation par petits groupes) ne sont refusées pour un terme verrouillé que si elles en perdent un que le texte avait ; un terme déjà absent ne fait plus refuser la correction d’un autre point du passage, comme le faisait déjà la relecture fusionnée. Une première traduction doit toujours porter chaque terme verrouillé. À la fin des tours, un terme verrouillé encore absent ne bloque plus : l’erreur vaut au passage tous les tours restants, comme avant, puis le passage est clos sur son texte et listé dans
residual_pointsavec le nouveau"motive": "locked_term_unmet"et le terme (source → traduction attendue), et le rapport estcompleted_with_residualsau lieu deblocked. L’alertelocked_termreste ouverte dans la page Qualité. Un texte resté dans la langue d’origine, un contrôle sans verdict et une erreur retenue par l’arbitre sans pouvoir être appliquée bloquent toujours. Voirdocs/autopilot.fr.md. Closes #379. - Termes verrouillés du glossaire : entre les mots d’une traduction verrouillée, l’espace et le trait d’union (
-, U+2010, U+2011) sont désormais la même graphie, dans les deux sens et dans toutes les langues écrites avec des espaces ; chaque mot garde son propre accord. Deux verrous voisins commemaid robots → robots-servantesetmaid robot → robot servantene pouvaient pas être satisfaits par une même phrase, et toutes les traductions du passage étaient refusées. Un terme réellement absent reste une erreur. L’analyse ne verrouille plus un nom dont la traduction figure telle quelle dans le texte du livre (ototo → younger brotherdans un livre traduit depuis l’anglais) : c’est une glose dans la langue source, gardée comme rendu préféré, avec une décisionskippedau journal. Refs #379. - Le contrôle de fidélité sémantique est désormais lu par le juge qualité configuré (celui du livre, sinon celui de l’installation) et non plus par le modèle qui a traduit. Réseau : avec un juge d’installation, chaque livre est envoyé à ce provider pour ce contrôle, y compris un livre traduit sur un modèle local ; Aucun juge pour ce livre garde le contrôle sur le provider du livre. Sans juge, ou quand le juge ne répond pas, le provider du livre lit comme avant. Chaque preuve enregistre le provider qui a lu (
provider_id). Voirdocs/quality.fr.md. Closes #360. - Une remarque de relecture dit désormais sur quels mots elle porte : chaque critique peut porter
source_quote(les mots de la source qui montrent le problème) ettranslation_quote(la formulation fautive), demandés par les quatre prompts de relecture (translation_review,quality_judge,review_revision,final_review, version de promptfile-v32) et par le schéma JSON lui-même : un prompt personnalisé reçoit donc aussi la consigne. Les deux sont facultatifs : une réponse qui ne les donne pas est lue comme avant. Quand une réécriture est relue, deux remarques d’une même catégorie sur un même paragraphe sont maintenant deux défauts si leurs extraits se trouvent à des endroits différents de la source, même quand aucune ne cite rien dans sa description ; des extraits qui se recouvrent sont un seul défaut, quelle que soit la façon dont la traduction réécrite est citée. Un extrait absent de la source du paragraphe est ignoré, et les remarques sans extrait (enregistrées avant la mise à jour, ou laissées vides par le modèle) sont rapprochées comme dans #359. Les positions sont des rangs de caractères : le japonais et le chinois sont placés comme les autres langues.backend/eval/critique_anchors.pymesure, sur une préproduction, combien de fois deux lectures d’un même texte sont distinguées. Closes #363. - L’interface ne télécharge plus tous les écrans avant d’afficher la page de connexion. Le premier fichier JavaScript contenait les paramètres, l’espace de traduction, les lecteurs, les statistiques et la documentation : 319 kB compressés, pour un visiteur qui voulait seulement se connecter. Chaque écran est maintenant chargé à l’ouverture de sa route : 100 kB pour la connexion, 156 kB pour la bibliothèque, 249 kB pour un livre avec son lecteur. Un écran affiche un état de chargement dans l’interface pendant l’arrivée de son fichier, et celui dont le fichier n’est plus disponible (une mise à jour l’a remplacé) propose de recharger l’interface. Le build échoue désormais si le premier fichier dépasse 130 kB compressés (#345).
- Interne : les panneaux du livre de
frontend/src/features/panels.tsx(2 300 lignes) ont chacun leur module —ProjectSettings.tsx,Glossary.tsx,Bible.tsx,Quality.tsx,Observability.tsx— avec ses libellés et ses traductions. Aucun changement de comportement, de texte ni de découpage du bundle (#347).
Corrigé
- Pilote automatique : une erreur de sens du relecteur est bloquante quel que soit le nom que le modèle donne à sa catégorie. Les prompts demandent l’un de quatorze noms de catégorie, mais rien ne le vérifiait, et le serveur comparait le nom à l’identique : une
errorrangée soussens,Mistraduction,contresensoufidélité(24 sur un seul livre) était un point de détail — ni tour supplémentaire, ni modèle supérieur, et le passage était clos en résiduel exportable. La catégorie est désormais lue à travers une table d’autres noms (casse, accents, espaces et traits d’union ignorés) là où toute critique est lue : les critiques enregistrées par les versions précédentes sont donc couvertes, et deux tours qui nomment différemment un même défaut sont comparés comme un seul défaut. Uneerrordans une catégorie que Libris ne connaît pas est bloquante et consignée dans le journal (critique category … is unknown) au lieu de passer pour un détail ; unwarningreste un avertissement, et une erreur de terminologie, sous n’importe quel nom, n’arrête toujours le livre que pour un terme verrouillé. Closes #382. - L’analyse ne prend plus un pronom ni un nom commun pour un nom. Sur un roman à la première personne traduit du français vers l’anglais, elle avait accepté puis verrouillé comme noms
moi → Narrator,mon père → Dad,ma mère → MotheretElle → Florence, et gardéla conseillère en orientationen français au titre de la politique qui conserve les noms : 245 réponses ont été refusées pour le seulmoi → Narratoret un tiers des passages a fini en erreur. Une proposition de nom dont la source ou la traduction est un pronom ou la désignation d’un personnage (narrateur, parent) est désormais retirée, avec une décisionrejectedau journal. Un nom écrit sans majuscule dans une langue qui en a (la psychologue,juge) n’est jamais verrouillé ni figé dans la langue source : il reste le rendu préféré, avec une décisionskipped. Un nom propre (Florence) est verrouillé comme avant, et un terme décidé par une personne n’est jamais touché. Un livre déjà analysé garde ses verrous : retirez-les dans l’onglet Glossaire, ils ne sont pas reproposés. Closes #381. - Un nom verrouillé dont la traduction reprend la forme d’origine avec un trait d’union (« Ino » → « Ino-sama », « Sora » → « Sora-san ») ne déclenche plus « Forme d’origine restée dans la traduction » sur un texte qui l’écrit : « Ino » à l’intérieur de « Ino-sama » était lu comme la forme source, et aucune réponse ne pouvait satisfaire le verrou. La forme n’est plus relevée que hors de la traduction verrouillée (« Ino » seul) ; trait d’union et espace sont une même graphie, comme dans #379. Par ailleurs, une alerte sur un terme verrouillé n’est plus close par le rejet de l’arbitre : son verdict est consigné, l’alerte reste ouverte tant que le texte ne porte pas le terme, et un passage clos sans lui figure au rapport (
residual_points,motive: locked_term_unmet) au lieu de laisser le verrou ni respecté ni signalé. Closes #380. - Une fiche de style qui demande des guillemets (
dialogue: guillemets) n’envoie plus la typographie française à un livre traduit vers une autre langue. Un livre allemand recevait « French quotation marks « » and an em dash for each change of speaker » et donnait— «Warten Sie hier», hat der Fährmann gesagt.; il reçoit désormais les guillemets de sa langue cible („ “ pour l’allemand, “ ” pour le portugais du Brésil contre « » pour celui du Portugal, 「 」 pour le chinois traditionnel), et seule une cible française garde « » avec le tiret à chaque changement d’interlocuteur. Le contrôle des dialogues suit : sur un tel livre il ne relève que les guillemets droits et nomme les guillemets de la cible, plus les français. Closes #365. - Un groupe nominal descriptif que l’analyse prenait pour un nom ne laisse plus son passage dans la langue d’origine ni le livre
blocked. Du chinois vers l’anglais, « 黑衣人 » → « black-clad agent » était verrouillé comme nom : toutes les traductions du chapitre étaient refusées (« horsemen », « the black-clad leader », un possesseur que l’anglais omet) et le texte original était gardé. Trois changements. Le pilote automatique ne verrouille plus un nom traduit écrit entièrement en minuscules : il reste au glossaire comme rendu préféré, et le journal des décisions le dit (skipped) ; un nom propre (« Li Santong ») est verrouillé comme avant, et un terme décidé par une personne n’est jamais touché. Un nom verrouillé écrit en minuscules qu’un paragraphe ne porte pas donne désormais un avertissement et non une erreur ; un nom propre et tout autre terme verrouillé restent des erreurs. Enfin, quand l’échelle de reprise est épuisée et que des réponses n’ont été refusées que pour leurs termes verrouillés, celle qui en manque le moins est conservée — après le contrôle de fidélité — et marquée à vérifier, avec l’alerterecovery_kept_translationqui nomme les termes ; un tel passage ne bloque plus le livre. Une réponse qui porte une autre erreur (texte non traduit, paragraphe recopié, longueur suspecte) cède toujours la place au texte original. Closes #374. - Sur téléphone, un livre au titre long ne fait plus défiler toute la page à l’horizontale : le dernier élément du fil d’Ariane est coupé par « … », comme prévu. Le fil d’Ariane gardait toute la largeur de son titre insécable (515 px dans une fenêtre de 320 ou 390 px), faute de pouvoir rétrécir dans l’en-tête de page. Les titres courts et les fenêtres plus larges ne changent pas. Closes #375.
- L’onglet Glossaire d’un livre ne défile plus à l’horizontale sur un écran de 768 px de large : les champs fichier natifs de « Reprendre une traduction existante » gardaient leur largeur intrinsèque et dépassaient de leur colonne (page large de 800 px). Un champ fichier ne dépasse plus jamais son conteneur, sur tous les écrans. Closes #376.
- Chinois → anglais : une matière nommée dans la source et remplacée par un mot général (古玉 rendu par « fine antiques ») est maintenant relevée et corrigée sans intervention. Un nouveau contrôle automatique,
named_material, signale un paragraphe dont la source nomme un objet de jade, de jadéite, d’ambre, d’agate, de corail, d’ivoire, de perle, de bronze ou d’une pierre précieuse (diamant, saphir, rubis, cristal…) quand la traduction ne porte aucun des mots anglais correspondants ; un mot pris dans un terme du glossaire (un nom) ou dans un composé figé rendu sans la matière (玉石俱焚, 琥珀色) n’est pas compté. La relecture finale lit désormais aussi les contrôles automatiques tels qu’ils sont sur le texte actuel, et plus seulement les alertes enregistrées à l’écriture du passage : un passage traduit avant l’existence d’un contrôle reçoit sa correction à la relecture suivante. La liste est écrite à la main pour cette paire et ne couvre que les matières : couleurs et autres objets nommés reposent toujours sur les règles des relecteurs. Closes #362. - Une Book Bible que le pilote automatique a validée seul n’est plus présentée au traducteur, aux relecteurs et aux juges comme la décision d’une personne.
EDITORIAL_BOOK_CONTEXTgardestatus: inferred(autorité la plus basse) tant quebible_auto_validatedest posé, le contexte narratif indique son origineanalysis, etSERIES_CONVENTIONSdit désormais qu’une décision de série non verrouillée prise par une personne (origin: series_decision) ne cède pas aux choix du livre : un « conserver Elysia » inféré ne l’emporte plus sur la décision de sérieElysia → Élysia, et le juge qualité et la relecture finale ne se contredisent plus à son sujet. Une bible validée à la main restevalidated. Closes #364. - Un point que l’arbitre rejette est maintenant clos même quand la réécriture demandée ailleurs dans la même réponse est refusée. Les rejets d’une réponse refusée étaient perdus : une erreur retenue par un arbitre puis rejetée par le modèle supérieur restait marquée confirmée, et un passage fidèle laissait son livre
blockedaprès trois tours. Les alertes des contrôles automatiques ne changent pas. Closes #366. - L’export d’un livre (
GET /api/projects/{id}/export/{format}) ne répond plus 422 quand le titre contient un caractère hors Latin-1 comme « — » ou 第一章 (livres créés par l’API v1 compris) : le nom du fichier passe en RFC 5987 (filename*=UTF-8''…), comme l’export de chapitre. Ferme #367. - L’aide et l’erreur placées sous un champ de formulaire sont désormais annoncées avec lui : les champs de saisie, les listes et les zones de texte d’un champ les désignent par
aria-describedby(après la description que l’écran donnait déjà, s’il y en a une), et un champ en erreur portearia-invalid. L’aide reste en dehors du nom du champ. Closes #341. - Un passage traduit en plusieurs parties pour une petite fenêtre n’est plus jeté par son propre contrôle de fidélité. Le contrôle reconstruisait une seule requête avec le passage et la traduction entiers, recevait
ContextTooLargeet laissait la source en place alors que les appels de traduction avaient été payés. Il se replie maintenant sur des groupes de paragraphes entiers, dimensionnés pour la fenêtre du juge (qui peut différer de celle du traducteur) : la moitié de la place va au texte, le reste au voisinage ; un paragraphe traduit en parties est lu partie par partie, chacune à côté de sa traduction. La place réservée à la réponse du juge est aussi calculée sur son vrai format de réponse, et non plus sur celui, bien plus gros, de l’analyse de chapitre, qui rendait le contrôle impossible pour tout passage dans une fenêtre de 16 384 tokens. Un paragraphe qui ne tient toujours pas, ou un groupe que le juge ne peut pas lire, laisse le contrôle « non concluant » comme avant : aucun verdict favorable n’est supposé. Closes #355. - Une réécriture n’est plus acceptée avec une nouvelle erreur sérieuse prise pour une ancienne de même catégorie dans le même paragraphe (une seconde négation perdue confondue avec la première, pendant qu’un autre paragraphe s’améliorait). Deux remarques d’une même catégorie qui citent des mots différents sont désormais deux défauts : la nouvelle compte comme ajoutée et le paragraphe reprend son texte précédent. Le même défaut reformulé reste reconnu, les descriptions n’étant pas comparées, et une remarque qui ne cite rien se rapproche par catégorie comme avant. Closes #359.
- Un passage confié au modèle supérieur pour un jeu de mots ou des vers y reste désormais sur tous les chemins de secours : traduction en parties après un contexte trop grand, réparations ciblées (paragraphes manquants, marqueurs cassés) et petits groupes après une réponse invalide. Ces chemins revenaient au modèle du livre, avec des parties dimensionnées pour la fenêtre du modèle supérieur. Si le modèle supérieur est en panne ou refuse le passage, le modèle du livre le reprend avec un contexte et des parties construits pour sa propre fenêtre, et le journal du pilote automatique le consigne (
stronger_model/fallback) (#357). - Un contrôle sémantique qui aboutit ferme maintenant l’alerte « contrôle non concluant » qu’une panne antérieure de la même étape avait laissée sur le passage, et retire cette panne du relevé de fidélité du job. Avant, un passage dont le contrôle avait échoué une fois (fournisseur indisponible) puis réussi restait « à vérifier », repartait à l’arbitrage, et le rapport le comptait comme non contrôlé. La panne d’une autre étape, les divergences et les preuves non vérifiables du nouveau verdict restent ouvertes. Closes #358.
- Les alertes traitées de l’onglet Qualité ne passent plus sous le contraste WCAG AA : l’opacité de 65 % de la ligne est remplacée par un fond en retrait et un texte atténué, deux paires de jetons déjà vérifiées à 4,5:1 dans les deux thèmes. Le badge « Traité » porte toujours l’état. Closes #349.
scripts/evaluate_analysis_modes.pyetscripts/benchmark_analysis.pyfonctionnent de nouveau depuis un environnement neuf : leur base jetable n’avait pas de licence, l’analyse restaitpausedet la commande documentée s’arrêtait sur uneAssertionErroravant son rapport. Les deux amorcent maintenant la licence synthétique signée de la suite de tests (backend/tests/synthetic_licence.py, partagée avecconftest) après chaque réinitialisation de la base. Avec plusieurs graines,calls_by_operationest désormais additionné sur toutes les graines commecalls(il gardait les chiffres de la première). Le rapport JSON de l’évaluation change de forme :{"seeds", "aggregation", "modes"}, oùaggregationindique que les ratios sont la moyenne des ratios par graine et les compteurs la somme sur les graines ; le tableau affiche la même ligne. Un test de fumée lance les deux commandes. Closes #361.- Écran « Édition du livre » : l’enregistrement envoie désormais la
revisionlue avec l’édition. Si quelqu’un d’autre a décidé entre-temps un champ que vous modifiez, le serveur refuse (HTTP 409) : le message s’affiche, votre saisie reste à l’écran et un bouton « Recharger l’édition » la remplace par la version enregistrée, au lieu d’écraser le titre de l’autre personne sans prévenir (#332). - Les appels ordinaires aux providers (complétions, liste des modèles) ne lisent plus en mémoire une réponse de taille quelconque : le corps est lu en flux et plafonné à
PROVIDER_RESPONSE_MAX_MB(8 Mo par défaut) de données décompressées, corps d’erreur compris. Au-delà, la connexion est fermée avant l’analyse du JSON et la requête est enregistrée en échec avec une erreur lisible ; une erreur HTTP garde son statut. Les plafonds des batchs ne changent pas. Closes #344. - Pont Codex : la base de traces que Codex tient dans le dossier de chaque compte (
logs_2.sqlite) ne grossit plus sans limite dans le volumecodex-state. Codex 0.160 y consigne chaque tour au niveau TRACE, sans réglage pour la borner ni la déplacer : 4,6 Gio et 3,9 Gio pour deux comptes sur une même instance, réécrits en continu et recopiés en entier à chaque sauvegarde. Le pont la vide désormais avant une génération dès qu’elle dépasse 64 Mio ; Libris ne la lit jamais, et le compte, sa connexion et les traductions en cours ne sont pas touchés. Un fichier trop gros laissé par une version antérieure est récupéré à la première génération après la mise à jour. Closes #371. - Sur la mise en page mobile (jusqu’à 900 px de large), chaque bouton, champ, onglet, option segmentée et entrée de menu est désormais une cible tactile de 44 px ; les petits boutons comme « Voir le rapport » faisaient 36 px, les actions principales 40 px, et à 768 px ils gardaient leur taille d’ordinateur sous le menu mobile. La densité sur ordinateur ne change pas. Un menu plus haut que l’écran, comme Exporter sur téléphone, s’ouvre désormais du côté où il y a le plus de place et défile au lieu de cacher ses dernières entrées, et ne dépasse plus du bord gauche d’un écran étroit. Un badge d’état plus long que son conteneur n’élargit plus la page quand le texte est agrandi. Closes #346.
- Les menus prennent le focus clavier à l’ouverture : la première entrée reçoit le focus une fois le menu positionné, les flèches, Début et Fin parcourent donc les entrées, et Échap ferme le menu en rendant le focus à son bouton. Le focus restait sur le bouton, et la flèche Bas faisait défiler la page. Closes #368.
- Bibliothèque en affichage mobile (jusqu’à 900 px de large) : les cases de sélection, les titres de livre et de série, la bascule Tableau/Cartes, le tri par statut, le lien « Voir un livre traduit… », le logo et le lien du fil d’Ariane sont désormais des cibles tactiles de 44 px. Les cases et le texte gardent leur taille ; c’est la zone qui reçoit le toucher qui s’agrandit autour. Une case ou un interrupteur avec son libellé, comme dans les paramètres, fait aussi 44 px de haut. L’ordinateur est inchangé. Closes #372.
- Affichage mobile (jusqu’à 900 px de large), hors bibliothèque : les cases « Verrouiller », « Accepter » et « Déroge à la série » du glossaire, la case de chaque passage à récupérer, la case de sélection d’un volume dans une série et la confirmation « J’ai retrouvé ce lot… » sont désormais des cibles tactiles de 44 px. Les cases gardent leur taille et leur nom accessible ; l’ordinateur est inchangé. Closes #373.
- Édition du livre : Échap, les boutons de fermeture et un clic à l’extérieur n’abandonnent plus les modifications non enregistrées. Une édition modifiée demande d’enregistrer, de fermer sans enregistrer ou de continuer, et quitter le livre demande avant de l’abandonner ; une édition inchangée se ferme aussitôt. Une sauvegarde en échec garde le brouillon, et une sauvegarde lente ne remplace plus ce qui a été saisi pendant qu’elle était en cours.
- Baisser la concurrence d’un provider borne désormais aussi les appels déjà en attente : l’admission compare les requêtes en cours à la limite actuellement enregistrée, relue sous le verrou d’admission, et non à celle chargée avant l’attente. Les appels réellement en cours se terminent ; une limite relevée s’applique aussitôt (#338).
- L’application s’ouvre de nouveau dans un navigateur qui refuse le stockage local (données de site bloquées, ou quota plein) : la page restait blanche, sans même le formulaire de connexion. Le thème, la langue, la barre latérale et la vue de la bibliothèque reprennent alors le réglage du système ou par défaut, et un choix fait vaut pour la session quand il ne peut pas être enregistré. (#339)
- Premiers pas : l’étape « tester la clé » n’est plus cochée par un appel au modèle encore en cours ou en échec (une erreur HTTP 401 la cochait). Il faut un test de clé réussi, ou un appel réussi, sur un provider encore utilisé, depuis le dernier changement de sa clé ou de son adresse ; remplacer la clé décoche l’étape jusqu’à ce que la nouvelle réponde (#342).
- La migration qui rattache les alertes de qualité à une révision du texte (
5c3e8d1a7b42) ne charge plus toutes les alertes et leurs messages en mémoire : les empreintes sont calculées par lots lus sur un curseur stable, et la base conserve le doublon ouvert le plus ancien. Le résultat est identique. Closes #343. - Assistant d’import : supprimer un fichier ne peut plus effacer l’envoi qui le suit. Un fichier supprimé libérait son numéro, l’envoi suivant reprenait ce numéro et le même nom de fichier sur le disque, et la suppression, terminée après son commit, effaçait le nouveau fichier : il apparaissait comme reçu mais manquait à la confirmation. Chaque fichier en attente a maintenant son propre nom de stockage, jamais redonné ; les numéros affichés dans l’assistant ne changent pas, et les imports commencés avant la mise à jour continuent de fonctionner. Aucune migration de base de données (#335).
- Un livre ne finit plus
blockedsur une erreur que le contrôle de fidélité conteste. Quand l’arbitre retient une erreur du relecteur et que le contrôle de fidélité refuse sa réécriture de ce même paragraphe lors de deux tours distincts, en citant chaque fois la source en faveur du texte en place, sans autre refus entre-temps, le point est clos sur le texte en place et listé dansresidual_pointsavec"motive": "contested_by_fidelity"(les autres entrées portent désormais"motive": "open_points") ; le livre finitcompleted_with_residuals. Un seul refus, un refus pour un autre motif (critique non résolue, erreur ajoutée, réponse invalide, contrôle sans verdict) ou une preuve qui ne soutient pas le texte en place bloquent toujours. Réf. #366. - Un polissage gardé en partie ne propose plus les termes de glossaire du candidat entier. Quand un paragraphe reprenait son texte précédent, les termes proposés par le modèle pour la formulation refusée étaient encore soumis, comme ses événements avant la 0.27.2 ; ils sont désormais écartés partout où le texte enregistré n’est pas le candidat (polissage, révision, correction du juge qualité). Un test de régression suit l’événement refusé jusqu’à la requête du passage suivant, que la reconstruction du récit échoue ou réussisse. Réf. #352.
[0.27.2] - 2026-10-04
Notes de mise à jour
- Aucune migration de base de données, aucun changement de licence. L’image du pont Codex change (CLI Codex 0.160.0) : l’installateur la récupère avec l’application ; un pont resté sur l’ancienne image est signalé comme un écart de version dans les Paramètres et continue de fonctionner avec l’ancienne liste de modèles. La sauvegarde planifiée (
deploy/libris-backup) met désormais en pause l’API et le worker (docker pause) pendant le dump de la base et l’archive des livres : les traductions s’arrêtent le temps de la sauvegarde et reprennent seules.LIBRIS_BACKUP_FREEZE=falsedanslibris-backup.confgarde l’ancien comportement.
Modifié
-
Pont Codex : CLI Codex 0.156.1 → 0.160.0, pour que la liste des modèles d’un compte ChatGPT propose ceux qu’OpenAI a ajoutés depuis, dont GPT-6.1 Sol (
gpt-6.1-sol). La liste est toujours lue auprès de l’app-server (model/list) : rien n’est codé en dur, le modèle d’un provider se choisit dans ses réglages comme avant. -
Un livre que le pilote automatique a laissé bloqué propose maintenant « Relancer le pilote automatique » comme action principale de son en-tête : un clic, sans confirmation, lance un nouveau passage du pilote. Le rapport reste à un clic (« Voir le rapport ») ; pilote désactivé pour le livre ou série en pause, l’en-tête affiche toujours « Voir le blocage ». Refs #348.
Corrigé
- Une réponse mal formée d’un provider ne laisse plus une requête marquée
running(#337). Unchoices,choices[0]oumessagenul, texte, liste ou de tout autre type erroné, comme une forme inattendue sur les transports Anthropic, Responses et Codex, se termine désormais par l’erreur de protocole connue (quelques essais bornés, puis un échec que l’appelant sait déjà traiter). Tout autre incident entre l’admission et l’enregistrement clôt la requête avec un statut d’erreur et sa durée, ce qui libère son créneau et sa réservation de budget ; une pause ou un résultat de lot tardif sont traités comme avant. - Le contrôle de fidélité sémantique n’écarte plus une divergence parce qu’un terme verrouillé quelconque du paragraphe a été corrigé. L’exemption exige désormais que la citation du juge soit ce terme et rien de plus (le terme tel que la source le dit, ou un fragment de sa propre entrée de glossaire) : corriger
sword → glaivene masque plus « was broken » rendu par « neuf », ni une référence culturelle modifiée dans le même paragraphe. Closes #351. - Les quatre relecteurs (relecture de traduction, relecture fusionnée, relecture finale, juge qualité) partagent désormais une même liste fermée de catégories et une même définition d’
error. Un défaut de sens que le relecteur étiquetaitgender,referencesoupronouns(donc traité comme un détail) devientmistranslationoupronoun, et une erreurpronoun(pronom, genre ou accord contraire à la source, à une fiche décidée ou à la série) garde un passage ouvert comme un contresens. Réf. #348. - Le pilote automatique ne finit plus
blockedpour des points de détail. Seule une erreur qui change ce que dit le livre (contresens, omission, ajout, texte non traduit, terme verrouillé) ou une erreur d’un contrôle automatique vaut un tour de plus à un passage ; à partir de sa deuxième lecture, la relecture finale ne garde un point nouveau que sur un paragraphe dont le texte a changé ; et une fois les tours épuisés, un livre n’estblockedque pour du texte resté dans la langue d’origine, un contrôle sans verdict, une erreur d’un contrôle automatique ou une erreur retenue par l’arbitre et non appliquée. Les autres points ouverts sont clos sur le texte actuel et listés dans le rapport (residual_points, issuecompleted_with_residuals, exportable). La relecture finale, la relecture fusionnée et le polissage gardent désormais les paragraphes qu’une correction améliore et ne rendent que ceux qu’elle abîme, au lieu de la refuser en entier. Le journal de la correction du juge qualité compte ses erreurs sur les paragraphes corrigés. Closes #348. - Une correction gardée en partie ne transmet plus aux passages suivants les événements du paragraphe refusé (0.27.1). Quand un paragraphe reprenait son texte précédent, la révision après relecture et la correction du juge qualité enregistraient encore les événements et proposaient les termes du candidat entier comme ceux du texte sauvé : un livre pouvait garder « Alice demeura vivante » et dire aux passages suivants « Alice died ». Le récit d’un tel passage est désormais marqué périmé et reconstruit à partir du texte enregistré, et les propositions de termes du candidat sont écartées. Ferme #352.
- Une correction gardée en partie est relue avant d’être enregistrée, et une phrase déplacée n’est plus coupée en deux (0.27.1). Le texte obtenu en remettant un paragraphe refusé n’est ni le texte précédent ni le candidat que le contrôle sémantique avait lu : il repasse désormais par ce contrôle (deux lectures de plus au maximum ; encore divergent, la correction est refusée en entier, comme avant la 0.27.1). Un paragraphe qui partage une phrase déplacée avec un paragraphe refusé reprend son texte avec lui, dans la correction du juge, la révision et l’arbitrage : remis seul, le paragraphe refusé disait la phrase deux fois, ou le passage la perdait. Ferme #354.
- L’échelle de récupération soumet désormais chaque candidat au même contrôle de fidélité qu’une première traduction avant de l’enregistrer. Une traduction refusée par le contrôle, ou sur laquelle il n’avait pas conclu, devenait le texte actif à l’étape suivante ; elle reste maintenant hors du texte, l’échelle passe à l’étape suivante, et le passage garde sa source (ou sa traduction précédente) si aucune étape ne donne un texte fidèle. Closes #350.
- L’aide et l’erreur placées sous un champ de formulaire sont désormais annoncées avec lui : les champs de saisie, les listes et les zones de texte d’un champ les désignent par
aria-describedby(après la description que l’écran donnait déjà, s’il y en a une), et un champ en erreur portearia-invalid. L’aide reste en dehors du nom du champ. Closes #341. - Un passage traduit en plusieurs parties pour une petite fenêtre n’est plus jeté par son propre contrôle de fidélité. Le contrôle reconstruisait une seule requête avec le passage et la traduction entiers, recevait
ContextTooLargeet laissait la source en place alors que les appels de traduction avaient été payés. Il se replie maintenant sur des groupes de paragraphes entiers, dimensionnés pour la fenêtre du juge (qui peut différer de celle du traducteur) : la moitié de la place va au texte, le reste au voisinage ; un paragraphe traduit en parties est lu partie par partie, chacune à côté de sa traduction. La place réservée à la réponse du juge est aussi calculée sur son vrai format de réponse, et non plus sur celui, bien plus gros, de l’analyse de chapitre, qui rendait le contrôle impossible pour tout passage dans une fenêtre de 16 384 tokens. Un paragraphe qui ne tient toujours pas, ou un groupe que le juge ne peut pas lire, laisse le contrôle « non concluant » comme avant : aucun verdict favorable n’est supposé. Closes #355. - Une réécriture n’est plus acceptée avec une nouvelle erreur sérieuse prise pour une ancienne de même catégorie dans le même paragraphe (une seconde négation perdue confondue avec la première, pendant qu’un autre paragraphe s’améliorait). Deux remarques d’une même catégorie qui citent des mots différents sont désormais deux défauts : la nouvelle compte comme ajoutée et le paragraphe reprend son texte précédent. Le même défaut reformulé reste reconnu, les descriptions n’étant pas comparées, et une remarque qui ne cite rien se rapproche par catégorie comme avant. Closes #359.
- Un passage confié au modèle supérieur pour un jeu de mots ou des vers y reste désormais sur tous les chemins de secours : traduction en parties après un contexte trop grand, réparations ciblées (paragraphes manquants, marqueurs cassés) et petits groupes après une réponse invalide. Ces chemins revenaient au modèle du livre, avec des parties dimensionnées pour la fenêtre du modèle supérieur. Si le modèle supérieur est en panne ou refuse le passage, le modèle du livre le reprend avec un contexte et des parties construits pour sa propre fenêtre, et le journal du pilote automatique le consigne (
stronger_model/fallback) (#357). - La mémoire de traduction ne reprend plus une traduction écrite sous une autre fiche de style. Un passage d’un autre livre n’est repris que si les deux livres ont la même fiche, série comprise : même temps du récit, même forme d’adresse par défaut, mêmes choix pour les honorifiques, les dialogues, le registre et les grossièretés, même tutoiement ou vouvoiement pour les couples nommés dans le passage, et aucune des formulations que la fiche remplace. Un livre réglé au présent reprenait telle quelle la traduction au passé simple d’un livre précédent, et en mode rapide aucune relecture stylistique ne la corrigeait. Dans un même livre, un passage renvoyé en relecture par un changement de la fiche de style n’est plus repris tant que cette relecture n’est pas réglée. Des vers et les mêmes mots écrits en une ligne de prose ne partagent plus la même entrée de mémoire : un poème de trois lignes ne revient plus en une seule ligne. Le réglage qui désactive la mémoire est inchangé. Closes #356.
POST /api/auth/forgotest désormais limité, en base de données pour que chaque processus de l’API et chaque redémarrage partagent le décompte : 10 requêtes par adresse client en 15 minutes et 30 par jour (IPv6 comptée par /64), refusées par un 429 avecRetry-Afterqui ne laisse aucune trace ; par compte, aucun nouveau lien ni courriel dans les 5 minutes qui suivent le dernier et 3 au plus par heure, avec la même réponse qu’un lien envoyé, que le compte existe ou non. Les liens précédents restent valables. Le compteur de demandes est distinct du frein aux échecs de connexion et une simple requête n’ajoute rien en mémoire du processus. Derrière un proxy,FORWARDED_ALLOW_IPSdoit être l’adresse du proxy, jamais*. Ferme #331.- Chaque 429 de la limite par client de
POST /api/auth/forgotest désormais journalisé enWARNINGavec son seau (l’adresse du client, ou le /64 en IPv6) et l’attente, sans rien du compte demandé. Un exploitant derrière un proxy inverse qui litbucket=172.18.0.1voit qu’il manqueFORWARDED_ALLOW_IPS. Ferme #377. - La sauvegarde planifiée (
deploy/libris-backup) n’annonce plus « written and verified » pour un dump de base et une archive des livres pris à des instants différents. Elle gèle l’API et le worker (docker pause) pendant les deux phases, échoue sans rien garder si un fichier du volume est ajouté, supprimé ou remplacé entre-temps, et enregistre le hash de chaque fichier archivé dansbooks.sha256, quelibris-restorevérifie après la restauration.LIBRIS_BACKUP_FREEZE=falsedésactive le gel. Closes #333. - Les textes d’état secondaires (pourcentage de progression, estimation, compteurs, indication du pilote automatique) atteignent désormais le contraste WCAG AA (4,5:1) sur les surfaces en creux et teintées d’accent, dans les deux thèmes :
--text-subtlepasse de#6a6f79à#5f646een clair et de#8e919aà#969aa3en sombre. Le test des tokens couvre maintenant--text-subtlesur--bg,--surface,--surface-sunkenet--accent-soft(#334). - Un fichier dont l’inspection se termine après la confirmation de l’import est désormais refusé (HTTP 409, « Cet import est déjà confirmé. ») au lieu d’être ajouté à une session déjà close : la vérification est refaite sous le verrou de la session, avant toute écriture. Les envois simultanés vers une session encore ouverte sont tous conservés (#336).
- Le mode batch ne répond plus à une question avec le résultat payé pour une autre. L’identité durable d’un appel en lot ne couvrait que le texte source du passage et les règles de l’utilisateur : deux contrôles de fidélité de candidats différents, un contrôle après le verrouillage d’un terme ou le réexamen d’un verdict contradictoire partageaient la même clé, et le second appel recevait le prompt et le verdict stockés du premier. L’identité couvre désormais toutes les entrées obligatoires de l’opération (traduction courante, précédente et candidate, propositions, glossaire verrouillé et termes de série verrouillés) ainsi que les consignes ajoutées après le prompt construit. Les passages voisins, les personnages de la scène et les termes de série non verrouillés en restent exclus : un résultat est toujours réutilisé après un redémarrage, sans seconde facturation. Un lot collecté par une version antérieure et encore en attente lors de la mise à jour est redemandé une fois. Closes #353.
- Deux personnes qui modifient l’édition du même livre ne s’annulent plus.
PATCH /api/projects/{pid}/editionlit désormais l’édition sous verrou de ligne : changer le texte alternatif de la couverture depuis une page chargée avant qu’une autre personne renomme le livre conserve le nouveau titre, et le titre de la bibliothèque, l’édition enregistrée et les métadonnées de l’EPUB restent identiques.GETetPATCHrenvoient unerevision; un client qui la renvoie reçoit un HTTP 409 quand un champ qu’il modifie a été décidé par quelqu’un d’autre depuis cette révision, au lieu de l’écraser. Sansrevision, la dernière modification l’emporte toujours. Le fichier d’une couverture remplacée n’est supprimé que si aucune modification ultérieure ne l’a choisi de nouveau. Aucune migration (#332).
[0.27.1] - 2026-10-04
Notes de mise à jour
- Aucune migration de base de données, aucun changement de licence. Les règles intégrées passent en
rules-v13.
Modifié
- Le score de qualité ne fait plus payer à un passage son historique : une récupération qui a abouti à une traduction (10 points) et une critique rejetée par l’arbitrage (2 points) sont listées sans coût. Une récupération qui a gardé l’ancienne traduction, une critique reportée et des points clos sans correction coûtent comme avant.
Corrigé
- Une correction n’est plus refusée en entier pour un seul paragraphe. La correction du juge qualité, la révision après relecture et l’arbitrage de l’autopilote jetaient la réécriture de tout un passage dès qu’un paragraphe gagnait une erreur, ou dès que le contrôle sémantique relevait une divergence : sur un chapitre d’un seul passage de 41 paragraphes, une correction qui faisait passer de 12 erreurs à 3 était refusée trois tours de suite et l’autopilote finissait
blocked. Un paragraphe refusé par le contrôle sémantique, les contrôles automatiques ou la seconde lecture garde désormais son texte précédent, et le reste de la correction est enregistré ; dans l’arbitrage, les critiques d’un tel paragraphe restent ouvertes pour le tour suivant (décisiondeferred) au lieu d’être closes. Un constat sur un paragraphe que la correction n’a pas touché ne lui est plus reproché. Rien n’est gardé quand aucun paragraphe modifié ne reste, quand le passage entier est mis en cause ou quand le contrôle sémantique n’a pas conclu. Un passage dont les paragraphes divergents ont été remis compte commepasseddans le rapport de livraison. Le polissage, la relecture fusionnée et la relecture finale ne changent pas. - Chinois → anglais : les règles nomment désormais des mots littéraires et de wuxia trompeurs (爛銀 est un argent étincelant, non terni ; 心脈 désigne les méridiens du cœur, non un pouls ; 虎口 ; 殺著) et demandent qu’une matière nommée dans la source (古玉) ne soit pas remplacée par un mot général.
[0.27.0] - 2026-10-04
Notes de mise à jour
- Deux migrations de base de données s’exécutent d’elles-mêmes au démarrage (
merge_repairs, puisquality_issue_revisions, une seule chaîne). La seconde ajoute à chaque alerte qualité la révision sur laquelle elle a été contrôlée ; les alertes existantes n’ont pas de révision connue et passent enrecheck: toujours ouvertes et listées en relecture, elles ne coûtent plus de points tant qu’un contrôle ultérieur ne les retrouve pas. Aucun changement de licence : compatible avec le serveur de licences 0.13.0 déployé.
Modifié
-
Le prompt de l’auditeur de fidélité prend désormais TARGET_TEXT et les choix obligatoires (identités confirmées, décisions humaines, glossaire verrouillé, conventions de série) pour seule référence :
PREVIOUS_TRANSLATIONdit seulement quelles unités ont changé, n’est jamais citée comme preuve, et une candidate qui la corrige en rejoignant la source ou un terme verrouillé n’est pas une divergence. Le juge renseignesupported_readingpour chaque divergence rapportée. Le corpus de fidélité gagne un genrecorrection(feelers/antennes avec terme verrouillé, et quatre cas « en réalité plus fidèle », chacun avec le français, l’anglais, le chinois et le japonais en cible) et un témoin négatif (terme verrouillé corrigé et nombre changé : toujours une divergence) ; ses tests ne vérifient que les réponses attendues, jamais une réponse observée. Les prompts intégrés passent enfile-v30(#326). -
Les deux migrations non publiées (
merge_repairs,quality_issue_revisions) forment désormais une seule chaîne :alembic upgrade headn’échoue plus sur deux têtes -
Un changement de la fiche de style (livre ou série) ou des consignes du livre, d’un chapitre ou d’un passage renvoie désormais en relecture les passages traduits que personne n’a validés, avec la raison (« La fiche de style du livre a changé. »), comme le faisaient déjà un changement de glossaire ou de formulation ; enregistrer la même valeur ne change rien.
GET /api/projects/{id}/styleet lerule_originsde l’inspecteur de contexte disent d’où vient chaque règle suivie par la traduction (volume, série, analyse, aucune), etGET /api/projects/{id}/glossary/effectivemarque d’unconflictune décision de série non verrouillée opposée à un terme du livre non verrouillé (celle de la série est gardée, personne ne l’a confirmée) (#329). -
Le banc d’évaluation du moteur réel (
python -m app.eval.run) fige désormais ses critères de non-régression (backend/eval/criteres.yaml) dans le manifeste avant le premier appel payant, etcompareles applique : une hausse des défauts manqués, des fausses alertes ou des verdicts indéterminés dans une seule dimension, une baisse du texte livré ou une hausse de coût au-delà de la tolérance sort avec le code 1 ; deux runs lancés sous des critères différents, ou un run arrêté, ne sont pas comparés. Un run nomme sa configuration de modèles (--configuration, deux documentées :luna,luna-sol) et peut utiliser un juge d’annotations distinct (EVAL_JUDGE_PROVIDER_ID). Il refuse de démarrer en CI ou sur une installation où des travaux sont en cours, s’arrête si un autre worker prend son travail, et laisse toujours unreport.jsonpartiel quand il s’arrête.EVAL_COMMITnomme le commit là où git est absent (#330). -
L’analyse d’un chapitre cite désormais la preuve de chaque alias :
aliases_evidencecontient, pour chaque alias donné à un personnage, la phrase exacte du passage qui désigne les deux noms comme une seule personne (une citation absente du passage est retirée ; les alias eux-mêmes sont gardés). Un alias n’est déclaré que si le texte l’attribue à la même personne ; sinon il va dansproposed_aliases, et deux personnages qui apparaissent ensemble, un titre ou un nom commun ne sont pas des alias. Une analyse ancienne sans ce champ se lit toujours. La fusion ne s’en sert pas encore. Promptsfile-v27(#324). -
Un profil de personnage qui cite le nom d’une autre fiche parmi ses alias ne devient plus cette fiche sur la seule parole du modèle : deux fiches non validées ne sont fusionnées, et un profil n’est rattaché à une fiche unique, que si une citation du passage (
aliases_evidence) nomme les deux et que rien ne l’interdit. Deux genres connus différents, un nom générique (« boss », « the bandit leader ») ou porté par deux fiches, une relation active entre les deux, ou l’analyse d’un même passage qui les décrit comme deux personnages les gardent séparés quelle que soit la citation. Un alias refusé part dans les alias proposés, où il apparaît comme suggestion de fusion ; la fiche note le refus (kept_apart: nom, motif, passage), qui tient pour toute décision automatique suivante jusqu’à ce qu’une personne fusionne les deux. Une fusion acceptée cite le passage et la phrase dans son motif. Un vrai pseudonyme sans phrase qui nomme les deux noms reste donc une proposition à valider, pas une fusion. Les fiches validées et les listes saisies par une personne se décident comme avant ; les fiches déjà fusionnées ne sont pas réparées ; la mémoire des passages précédents et la bible de série suivent séparément (#324). -
La mémoire des passages précédents reconstruite par l’analyse parallèle et la bible de série suivent désormais la règle de preuve des alias déclarés. Rejouée dans l’ordre du livre, une analyse qui cite le nom d’une autre identité parmi ses alias ne la rejoint que sur une citation (
aliases_evidence) qui nomme les deux, et jamais entre deux genres différents, pour un nom générique ou partagé, quand une relation lie les deux, quand un même passage les décrit comme deux personnages ou après un refus : une analyse stockée sans citation ne fusionne plus deux identités. L’enregistrement daté d’un personnage ne revient jamais à une fiche dont il a été gardé séparé. Dans une série, la fiche d’un volume ne rejoint une identité de série connue sous un autre nom que si une citation gardée sur une fiche liée (alias_quotes, les 20 dernières) nomme les deux noms ; sinon le lien est une proposition à confirmer. Un nom noté danskept_apart, ou le nom d’une autre identité de série, n’est jamais versé dans les alias d’une identité de série, et un refus l’en retire si un calcul précédent l’y avait mis. Les liens faits par une personne sont conservés. Les fiches analysées avant cette version n’ont pas de citation : leurs liens existants restent, les nouveaux liens sous un autre nom sont proposés (#324). -
Le
max_connectionsde la base se règle désormais parPOSTGRES_MAX_CONNECTIONSdans.env(200 par défaut, inchangé), et le nouveau réglageWORKER_PROCESSES(1 à 16, 1 par défaut) dit combien de processus worker s’en partagent. Au démarrage, l’API et le worker comparent lemax_connectionsde PostgreSQL à(1 + processus worker) × (DB_POOL_SIZE + DB_POOL_MAX_OVERFLOW) + 20et journalisentdb_pool=over_budgetavec la valeur à poser quand il est trop bas ; ils démarrent quand même. Rien ne change avec un seul worker (#322). -
Les couples tu/vous des règles de style d’un livre s’écrivent en une ligne par forme au lieu d’une phrase par couple : 100 couples coûtent environ 1 000 jetons au lieu de 19 256 dans chaque prompt. La phrase forte reste à côté du passage (
ADDRESS_FORMS) pour les couples qui y figurent. Au-delà de 100 couples lus, la coupe garde les plus lus, non les premiers lus. Règles de promptrules-v11(#321).
Ajouté
-
API de contexte narratif pour les autres applications de l’écosystème (Libris Draw) :
GET /api/v1/books,GET /api/v1/books/{id}/narrative-context,GET /api/v1/books/{id}/narrative-context/revisionetGET /api/v1/series/{id}/narrative-contextrépondent un instantané versionné d’un livre — chapitres, passages avec leur source et leur traduction en vigueur, Book Bible, fiches des personnages avec alias, mentions et observations sourcées, relations, lieux et objets, glossaire, événements — avec les identifiants stables de Libris, uneprovenancesur chaque élément, et des empreintes (revision,content_revision, une par chapitre,checksum) qui disent à un client si son instantané est encore à jour. Lecture seule, sous la nouvelle permission de jetonnarrative:read; aucune migration de base. -
Une mauvaise fusion d’identités se répare, une fiche absorbée à la fois (#325).
GET /api/projects/{pid}/characters/merges/{mid}/repair?source_id=en donne l’aperçu sans rien écrire : la chaîne de fusions lue dans le journal (A → B → C), la fiche rendue depuis son instantané, les noms, champs, éléments de liste et relations qui lui reviennent, ceux qui restent et ceux que personne ne peut attribuer.POSTsur le même chemin applique cet aperçu en une seule transaction (plan_token; 409 si la mémoire a changé depuis, 409 avec son motif si le journal n’a pas l’instantané), consigne le rapport sur la fusion (repairs, exporté avec le livre) et dans le journal d’audit, et renvoie le rapport stocké s’il est rejoué. Ce qu’une personne a décidé, validé ou ajouté après la fusion n’est jamais retiré ; un élément sans provenance reste en place, listé pour arbitrage (decisions:source,targetouboth), jamais attribué au hasard. Les nouvelles fusions enregistrent les relations telles qu’elles étaient et les rendent à l’identique ; les fusions plus anciennes ne récupèrent que les relations que l’analyse du passage attribue. Les deux fiches deviennent des identités confirmées : une analyse ultérieure propose mais ne les refusionne plus ; les passages traduits non validés qui citent l’une ou l’autre sont marqués à recontrôler, aucune traduction n’est réécrite, et une identité de série encore partagée par les deux est signalée, non modifiée. L’écran suit séparément. -
L’historique des fusions de l’écran Personnages est désormais une liste lisible, avec un bouton « Réparer » pour chaque fiche absorbée. La fenêtre montre l’aperçu avant toute écriture : ce qui revient à la fiche rétablie, ce qui reste sur la fiche actuelle et pourquoi, les passages qui seront revérifiés, et un choix (fiche rétablie, fiche actuelle, les deux, ou laissé tel quel) pour chaque élément que personne ne peut attribuer. Un refus du serveur est affiché avec sa raison, et une fiche réparée est marquée « Réparée » (#325).
-
Le banc d’évaluation mesure la fiabilité des diagnostics et des corrections acceptées face aux micro-cas de référence (
app.eval.reliability) : TP/FP/TN/FN avec dénominateurs, corrections justes acceptées ou rejetées, corrections dégradantes acceptées, indéterminés à part (jamais un succès), chaque résultat relié à sa source, son candidat, son diagnostic, sa décision et son texte enregistré, avec coût, appels, tokens, durée, reprises et escalades, et un intervalle à 95 % qui signale les petits effectifs. Aucun appel de modèle ; tourne en CI (#330). -
Un jeu de référence de 48 micro-cas synthétiques CC0 (
backend/eval/micro/, six catégories de difficulté, six couples de langues) pour mesurer les faux diagnostics et le sort des corrections proposées : chaque cas porte une source, une traduction initiale, un candidat éventuel, le contexte et une référence justifiée écrite avant tout run, avec des témoins corrects et les désaccords d’une seconde annotation à l’aveugle laissés visibles.read_microle valide sans appel de modèle et refuse un run réel sur un jeu non relu ou modifié après sa relecture (#330). -
WORKER_PROCESSES(1 par défaut, inchangé) permet au conteneur worker d’exécuter les livres dans plusieurs processus, un cœur chacun : avec N ≥ 2, le worker garde toutes les boucles périodiques (licence, sources suivies, rétention, courriels, mémoire) et lance N processus de travaux qui partagent la file par ses baux et verrous existants. Un processus laisse le livre suivant aux autres dès qu’il en tient plus que sa part, un processus de travaux mort est relancé et ses livres sont repris à l’expiration de leur bail, et l’arrêt est transmis puis attendu dans les 30 secondes du délai de grâce. Un livre seul reste sur un cœur ; un seul conteneur worker ; chaque processus a son propre pool de connexions (#322). -
Quand la synthèse de la Book Bible est trop grande pour son provider, l’avertissement « sections non consolidées » du livre nomme le provider utilisé, sa fenêtre de contexte et sa réserve de réponse, et les jetons demandés face à ceux disponibles ; il cite les providers configurés dont la fenêtre suffit (ou la fenêtre à configurer, en précisant qu’un provider réglé à 100 000 jetons suffit quand c’est le cas), avec un bouton vers les réglages du livre (#319).
Corrigé
-
L’autopilote ne verrouille plus un nom descriptif que d’autres personnages portent aussi : 黑衣人 (« homme en noir ») était verrouillé comme un nom propre (« Black-Clad Rider ») alors que deux autres personnages s’appellent 持銅錘的黑衣人 et 使鏈子鏢的黑衣人 ; chaque traduction du chapitre était donc refusée (« Traduction verrouillée absente »), à chaque étape de récupération et avec les deux modèles. Un tel terme reste au glossaire, accepté et non verrouillé.
-
Une alerte qualité sait désormais sur quel texte elle a été trouvée (#328). Chacune porte la révision du passage et de la mémoire du livre sur lesquelles elle a été contrôlée, son origine et un état :
active(trouvée sur le texte actuel),recheck(le texte ou la mémoire a changé depuis, ou la révision est inconnue : toujours ouverte et dans la liste de relecture, mais elle ne coûte plus de points),resolved(un contrôle ultérieur ne la retrouve plus),rejected(jugée fausse par une personne ou l’arbitrage) ouhistorical(close sans preuve). Plus rien n’est supprimé : un passage corrigé garde l’historique de ce qui a été réglé, un défaut non corrigé est confirmé sur place au lieu d’être réécrit, et une alerte écartée par une personne n’est pas rouverte par le contrôle global suivant. La base refuse deux alertes ouvertes pour le même défaut (34 doublons exacts s’étaient accumulés) et une alerte close sans motif ; un résultat calculé sur une révision que le passage a quittée est ignoré. Un changement de mémoire seul fait passer les alertes ouvertes enrechecksans en clore aucune. Le score, les compteurs d’alertes ouvertes (issues_active,issues_recheckdu rapport de complétude) et la liste des alertes s’accordent désormais ;GET /projects/{id}/issuesliste les alertes ouvertes avecstate,origin,segment_revision,memory_revisionetcurrent, et?history=trueajoute les closes. Les alertes existantes gardent leurs lignes : la migration les marquelegacyavec une révision inconnue (les ouvertes enrecheck, les closes enhistorical, les doublons exacts d’une alerte ouverte enhistorical), le worker rejoue sans appel à un modèle les contrôles automatiques gratuits, et les archives de projet portent les nouveaux champs (une archive plus ancienne restaure ses alertes enlegacy). Les scores peuvent remonter après la mise à jour, puisque les alertes non prouvées sur le texte actuel ne comptent plus. -
Toutes les étapes qui écrivent, relisent ou jugent une traduction suivent désormais le même ordre de consignes, et plus le seul traducteur : règles explicites et fiche de style du livre (celle du volume, puis de sa série), décisions d’une personne, glossaire verrouillé, termes de série verrouillés, puis faits validés, mémoire et inférence. La Book Bible envoyée avec un passage dit si une personne l’a validée (
status:validatedouinferred) et ne répète plus ce que la fiche de style décide (temps, honorifiques, convention de dialogue) : une relecture ou un arbitrage ne ramène plus le temps que l’analyse avait déduit. Le contrôle de cohérence construit ses règles avec le même code que le contexte d’un passage. Promptsfile-v28, règlesrules-v12(#329). -
Un diagnostic de relecture que rien n’étaye est écarté avant d’alimenter une correction, un arbitrage ou un compteur de points ouverts. La relecture, le juge qualité, la relecture finale, le contrôle de cohérence global et l’arbitrage qualifient désormais trois cas sans modèle, dans toute langue : une unité que le passage n’a pas, des mots cités à l’appui d’un remplacement et introuvables dans le passage, et un remplacement identique au texte actuel (« ? » remplacé par « ? » ; espaces et typographie mis à part, casse conservée). Les unités sont lues avec leur passage : une remarque sur une unité réduite à un signe ou à une balise n’est ni toujours gardée ni toujours écartée, et un avertissement sans remplacement reste possible. L’arbitre apprend qu’une justification est une affirmation à vérifier et marque une proposition rejetée
missing_evidenceoucontradicted_by_context(un raisonnement que la source en contexte contredit, même avec une citation exacte). Chaque diagnostic écarté est inscrit au journal des décisions avec son motif, clos, et n’est pas redemandé. Les remarques de cohérence et les critiques enregistrées par les versions précédentes sont filtrées quand l’arbitrage les lit. Les prompts intégrés passent enfile-v29(#327). -
Une correction n’est plus refusée par la preuve même qui lui donne raison (#326). Le contrôle de fidélité sémantique prenait pour un refus toute divergence dont la citation existait dans la source ou dans un choix obligatoire : une révision qui rétablissait un terme verrouillé (« feelers » → « antennes » à la place de « palpitations ») était rejetée par la citation « feelers », et le contresens restait. Le serveur écarte désormais une telle divergence quand le candidat dit la traduction verrouillée d’un terme de l’unité source et que l’ancien texte ne la disait pas (catégories identité d’objet et technique nommée seulement) : la correction est enregistrée, le contrôle est noté
passedavec le motifcontradicted_by_evidence, et un point de relecture en avertissement garde la description du juge. Toute autre divergence vérifiée de la même unité (négation, nombre, agent, blessure, résultat) refuse toujours le candidat, et une citation tenue seulement d’une décision humaine n’est jamais écartée. Le juge dit maintenant quelle version sa citation soutient (supported_reading) ; s’il refuse un candidat sur une preuve qu’il dit en sa faveur, il est réinterrogé une seule fois (deux appels au plus) : le second verdict tranche (reexamined), et un verdict encore contradictoire, comme un provider indisponible, donnenot_runet conserve le texte précédent. -
Un volume de série qui attend un volume précédent n’est plus relancé toutes les 15 secondes pour se remettre aussitôt en attente : la file vérifie le volume précédent sans prendre le travail, et ses tentatives, ses lignes de journal et son état ne bougent plus tant qu’il ne peut pas réellement continuer. Un tel travail avait atteint 8 492 tentatives en deux jours (#323).
-
Un livre dont le rapport d’autopilote est
blocked, ou dont un ancien rapportcompleted_with_residualslaisse des passages ouverts, s’affiche désormais comme non prêt sur sa page : le rapport est recompté et bloque le livre, et l’action principale reste « Voir le blocage » même quand l’autopilote est désactivé pour ce livre (#320). -
La relecture finale n’échoue plus en
ContextTooLargesur un passage portant des centaines de remarques de cohérence, même avec une fenêtre de 100 000 jetons (#321) : ses contrôles antérieurs sont limités à 20 lignes distinctes et 6 000 jetons, erreurs d’abord, avec un compte « +N autres », et ses critiques antérieures à 6 000 jetons, en contexte complet comme réduit. Une remarque de cohérence réécrite reste une seule ligne, un passage en garde au plus 5 ouvertes, et une revérification à une nouvelle révision résout les remarques écrites avant elle. -
Une Book Bible trop grande pour accueillir ne serait-ce qu’une section de plus ne bloque plus toute l’analyse : les nouvelles sections sont synthétisées en un lot séparé avec le même provider, puis jointes à la Bible sans perdre un fait de l’une ou de l’autre (listes fusionnées, les deux résumés gardés). Un volume dont la Bible dépassait de quelques pour cent l’entrée laissée par son provider finit avec toutes ses sections consolidées et passe à la traduction au lieu de s’arrêter sur
analysis_unconsolidated(#319). -
La relecture automatique qui suit une décision modifiée se termine maintenant par son propre rapport d’autopilote, recompté sur les passages tels qu’elle les laisse ; dernier travail du livre, elle n’en portait aucun, et les tomes 21 à 23 de DxD semblaient finis sans rapport (#320).
[0.26.0] - 2026-10-02
Notes de mise à jour
- Aucune migration de base de données n’est nécessaire. Le certificat de licence peut désormais porter une date
updates_untilfacultative ; les certificats sans cette date et les licences perpétuelles restent sans limite. Compatible avec le serveur de licences 0.12.3 déployé.
Ajouté
-
Le tamoul (
ta) figure parmi les langues source et cible de l’assistant d’import et des réglages du livre (#313). -
Tamoul (
ta) comme langue source et cible (libris/libris#313) : proposé parGET /api/languages, avec sa typographie dans le prompt (ponctuation latine sans espace avant, guillemets “ ” ; règlesrules-v10), son écriture pour le contrôle de texte non traduit, et aucune règle française ou espagnole appliquée. Les limites de mots comptent désormais toute marque Unicode et les liants ZWNJ/ZWJ comme lettres du mot (LIB-664) : un terme de glossaire, un nom ou un terme verrouillé n’est plus trouvé au milieu d’un mot tamoul ou hindi plus long (மன் dans ராமன், राम dans रामू) ; le pliage des accents retire les accents mais jamais un signe indien (கண் n’est pas கண). Un nom tamoul est reconnu avec son suffixe casuel dans la source et dans une traduction verrouillée (ராமன் → ராமனுக்கு). Le quota compte les mots tamouls en séparant les mots par des espaces ; le ratio de longueur anglais → tamoul (environ 0,9 à 1,4) reste dans les bandes existantes. -
Un livre n’est plus affiché « Terminé » quand il n’est pas prêt : le serveur calcule un état affiché
display_state(blockedquand l’autopilote s’est terminé bloqué,to_checktant que des passages restent à vérifier, en erreur ou refusés ou que le rapport garde des résidus,completedseulement sans l’un ni l’autre), distinct deprojects.status, qui ne change pas. Il accompagne les livres et les volumes d’une série (display_state, aussi dansprogress),GET /api/v1/series/{id}et la liste des livres du MCP (#305). -
Nouvelles versions d’une licence Personnelle (phase A de libris/libris-licence#46) : l’image embarque la date du commit dont elle est construite (
app.released, écrite par le build depuisCI_COMMIT_TIMESTAMP, jamais lue dans l’environnement ; une image de développement n’en a pas et n’est jamais hors période). Le certificat peut porterupdates_until(secondes Unix) ; absent,null, 0, une valeur qui n’est pas un nombre ou un certificat perpétuelv: 2veulent dire sans limite, et un serveur de licences v1 n’a rien à changer. Réglages › Licence affiche « Nouvelles versions jusqu’au » etGET /api/settings/licencedonneupdates_until,released_atetcovered; le bandeau de mise à jour signale, sans masquer la commande d’installation, qu’une version annoncée peut ne pas être incluse une fois cette date passée. Rien n’est bloqué : le blocage des traductions et le contrôle de l’installateur viennent en phase B. -
Interface de démonstration en lecture seule (DEMO_MODE) : quand
GET /healthréponddemo: true, un bandeau « Démo en lecture seule » avec un lien vers l’essai gratuit s’affiche sur la page de connexion et sur chaque écran ; l’import, le lancement d’une analyse ou d’une traduction, l’édition du livre, la publication, WebDAV, l’archivage, les modifications des glossaires partagés et l’écran du compte sont masqués, la lecture et les exports restent disponibles. Toute autre écriture est arrêtée avant d’atteindre le serveur avec la même explication (#282). -
Sur une instance de démonstration dont
GET /healthréponddemo_login: true, un visiteur sans session entre directement dans la démo (POST /api/auth/demo) ; après une déconnexion, la page de connexion propose un bouton « Entrer dans la démo » au lieu de reconnecter d’elle-même (#294). -
La démo en lecture seule masque aussi les commandes d’écriture restantes de l’éditeur (traductions en lecture seule, ni enregistrement, validation, retraduction, consignes ni modification dans l’inspecteur du passage) et affiche en lecture seule les onglets Book Bible, Personnages, Glossaire et Réglages d’un livre, les pages de série et le détail d’un glossaire partagé (champs non modifiables, plus d’« Ajouter un terme »), ainsi que les priorités de la file d’attente. Le serveur continue de refuser toute écriture (#290).
-
Dans la démo en lecture seule, une sélection de livres (bibliothèque) ou de volumes (série) ne propose plus qu’« Exporter les EPUB » (ni Configurer, Analyser, Traduire, ni menu), et un livre sans provider n’affiche plus le bandeau de configuration du provider (#292).
-
Liste des premiers pas sur la bibliothèque pour un administrateur : activer la licence, ajouter un provider, tester sa clé, importer un premier livre avec son estimation, changer le mot de passe administrateur d’origine. Chaque étape se coche d’elle-même d’après
GET /api/onboarding, mène à son écran (#settings/licence,#settings/providers, l’assistant d’import, le compte) et la liste disparaît une fois tout fait ou masquée ; elle ne bloque rien. Paramètres › Providers LLM propose des modèles OpenAI, Anthropic, OpenRouter et serveur local pour un nouveau provider et avertit quand aucun prix n’est saisi, puisque les estimations afficheraient alors 0 €. La liste renvoie vers la vitrine d’un livre traduit de bout en bout sur libris-translate.com (#283). -
Guide opérateur de la démo : activer le mode lecture seule, charger les livres vitrine avant activation et réinitialiser depuis des archives de projet ; les livres restaurés comptent dans le quota de licence.
Modifié
-
L’estimation de coût ne mélange plus les langues cibles (libris/libris#314) : l’historique des livres du compte ne sert qu’aux livres écrits dans la même langue cible (
fr-FRetfrne font qu’un), si bien que des livres français ne règlent plus l’estimation d’un livre tamoul, et un premier livre tamoul est estimé avec des valeurs par défaut calibrées sur l’essai mesuré anglais → tamoul de LIB-670 (3,7 fois les appels, 1,1 fois les jetons d’entrée et 1,4 fois ceux de sortie d’un appel : environ 3,3 M en entrée et 240 k en sortie pour 3 700 mots, contre 0,8 M et 47 k avant). L’estimation d’import (GET /api/imports/{id}/estimate) accepte untarget_languagefacultatif, par défaut celui du volume cible ; sans lui, elle garde tout l’historique et les valeurs par défaut moyennes. -
Les paires de personnages dont le passage parle (tutoiement/vouvoiement) sont rappelées dans une section
ADDRESS_FORMSjuste avant le passage, dans toutes les requêtes sauf les analyses. Une paire parmi trente dansUSER_RULESétait lue comme une ligne de plus : sur le passage du Pigeon d’Alice, le modèle disait « vous » 4 fois sur 4 malgré une paire au tutoiement, et 0 fois sur 4 avec la paire rappelée près du texte (LIB-625). -
Les vers gardent leurs lignes, leur rime et leurs mots inventés (libris/libris LIB-622) : un passage d’au moins trois lignes courtes (poème, chanson, refrain, Jabberwocky) est traduit par le modèle supérieur quand il y en a un, avec une section
VERSEqui demande le schéma de rimes et la mesure de la source, une ligne pour une ligne, et un mot inventé recréé : forgé une fois, repris partout (new_terms), jamais laissé à moitié dans la langue source. Chaque prompt de correction et de relecture précise aussi que les vers se corrigent et se jugent comme des vers (règlesrules-v9). Le journal compte ces passages au modèle supérieur (verse). -
Une sortie machine en espagnol ne garde plus d’espace après les ¿ et ¡ ouvrants (« ¿ Te gustarían…? » devient « ¿Te gustarían…? », marqueurs inline compris) : Libris l’applique à chaque écriture machine et à chaque sortie, comme la typographie française. Rien d’autre ne change en espagnol, et la phrase qui dit aux relecteurs que Libris compose la typographie reste réservée au français (#311).
-
Le contrôle de traduction signale une forme concurrente d’un nom traduit (libris/libris#302) : le nom seul ne passe plus quand un autre mot à majuscule le suit (« Lapin Rose » pour « Lapin Blanc »), et un nom espagnol, italien ou portugais ne s’accorde plus qu’en genre (« Loro » n’est pas « Lori »). Des tests couvrent White Rabbit, Mouse, Duck, Lory et Dodo en français et en espagnol.
-
Les noms descriptifs de personnages sont traduits par défaut (libris/libris#302) : un nom formé de noms communs ou d’adjectifs (le Lapin Blanc, la Souris, le Canard, la Reine de Cœur) est proposé dans sa forme cible par l’analyse des chapitres (français : Lapin Blanc, Souris, Canard, Reine de Cœur ; espagnol : Conejo Blanco, Ratón, Pato, Reina de Corazones), une seule forme par personnage ; seul un vrai nom propre (Alice, Dinah) garde sa forme, et la politique
name_policyde la Book Bible ne concerne plus que les noms propres. L’autopilote verrouille la forme donnée par l’analyse quelle que soit la politique, même sans politique, et ne fige plus en anglais un nom-titre venu de la liste des personnages. Le contrôle de traduction accepte le nom seul pour un nom de deux mots (« Lapin » pour « Lapin Blanc » ; « Reine » pour « Reine de Cœur ») et signale la forme d’origine restée dans un nom traduit (« White Rabbit », « Rabbit »). Les prompts intégrés passent enfile-v25. -
Le guide du premier livre commence par l’activation de la licence.
-
Un provider raisonnant qui ne répond qu’une fois
reasoning_effortramené ànone(Qwen sous vLLM qui ignoreminimal) reçoit désormaisnoned’emblée aux appels suivants, par provider, modèle et effort configuré, au lieu d’épuiser tout le budget de sortie en raisonnement à chaque requête (#277). -
Le test d’un provider explique le cas d’un modèle qui épuise son budget de sortie en raisonnement sans répondre, lu dans ses derniers appels (
reasoning) : combien des dernières requêtes se sont arrêtées sur du raisonnement sans contenu près demax_output_tokens, niveau de raisonnement envoyé, conseil de le régler sur « Désactivé » (reasoning_effort=none) et bouton qui le fait dans le formulaire (#277). -
Le test d’un provider (
POST /api/providers/{id}/test) signale maintenant que les dernières requêtes se sont arrêtées sur du raisonnement seul, proche demax_output_tokens, sans contenu (serveur qui ignore l’effort demandé, comme Qwen sous vLLM) : nouveau champreasoninget message explicite, lus dans les requêtes déjà journalisées, sans erreur si le détail d’usage est purgé ou absent (#277). -
L’analyse de chapitre ne rejette plus toute la réponse pour une variante de formulation : un
kindd’événement écritfact(ouaction,events…) est lu commeworld_fact(event…) et unkindinconnu comme un simple événement ; lesrelationships,translation_notesd’un personnage et leurs preuves envoyés en une seule chaîne deviennent une liste d’une ligne. Une structure fausse (objet, nombre), le genre, les pronoms et les alias restent refusés (#278). -
Les formes d’adresse ne changent plus entre deux personnages au fil du livre : l’analyse de chapitre indique, citation à l’appui, si chaque paire qui se parle dans un passage se tutoie ou se vouvoie (tú/usted, du/Sie) ; la première lecture fait foi, et chaque passage, sa relecture et la relecture finale la reçoivent comme une règle de la fiche de style. Une paire décidée dans la fiche de style (du volume ou de la série) l’emporte toujours sur l’analyse ; une analyse forcée oublie ce que la précédente avait relevé. Les cibles espagnoles gardent une seule forme au pluriel : ustedes seul pour
esetes-419, vosotros poures-ES. Les deux relectures signalent comme erreur une réplique qui change la forme d’adresse d’une paire ou une narration qui quitte le temps du récit de la fiche. Promptsfile-v19, règlesrules-v8(#273). -
Les formes d’adresse relevées par l’analyse sont un vote par lecture : un couple n’a qu’une ligne quel que soit le nom sous lequel il a été lu (nom canonique, alias ou nom traduit de la fiche personnage, dans un sens ou dans l’autre, par exemple
Cheshire Cat/Chat du Cheshire), et c’est la forme la plus lue qui fait foi, non la première : une lecture bruitée ne décide plus du livre entier. À égalité, la forme lue en premier tient, la paire est marquéetiedansProject.configet journalisée. Une paire décidée dans la fiche de style l’emporte aussi sur une lecture de l’analyse qui nomme le même personnage autrement (#306). -
Les règles de paire de la fiche de style précisent que la forme vaut dans les deux sens et dans chaque réplique des deux personnages, sans jamais l’autre forme, même une fois (#303). Mesuré sur l’extrait M2 français avec la paire dans la fiche : le traducteur glissait encore un « vous » à la Souris dans 3 essais sur 6 avec l’ancienne formule, dans 0 sur 5 avec celle-ci.
Ajouté
-
Édition du livre : un interrupteur par livre pour la mention « traduction assistée par IA » lisible par machine des exports, activée par défaut, avec une phrase qui l’explique ;
GET/PATCH /api/projects/{id}/editionl’exposent enai_disclosure(valeur effective), avecai_disclosure_defaultetai_disclosure_book(choix propre au livre, null = suit l’installation) (#284). -
Chaque EPUB exporté par Libris (traduit, bilingue et exemplaire de lecture) indique désormais dans ses métadonnées que la traduction a été assistée par IA : un
dc:contributorau rôle de traducteurtrl(« Libris Translate (traduction assistée par IA) »),libris:ai-assisted-translationet la version de Libris (libris:version). En EPUB 3, le préfixelibris:est déclaré sur le paquet ; en EPUB 2, desmetaname/content. Les constructeurs acceptentdisclosure=Falsepour l’omettre ; la mention qu’un EPUB source portait déjà est remplacée, jamais dupliquée. Le paramètre inutilisécreditde la reconstruction EPUB est supprimé (#284). -
DEMO_MODE=truefait une instance de démonstration en lecture seule : toute écriture par l’interface,/api/v1et/mcpest refusée en 403demo_read_only, sauf la connexion et la déconnexion (second facteur compris) et les exports groupés EPUB et texte ; SSO, LDAP et/mcpsont fermés ; le worker ne lance aucun travail ni aucune scrutation, seulement le heartbeat de licence ;/healthréponddemopour l’interface (#282). -
DEMO_USERNAME(avecDEMO_MODE) connecte les visiteurs à ce compte sans mot de passe parPOST /api/auth/demo;/healthréponddemo_login. Le compte doit exister, être actif, local, sans second facteur et non administrateur, sinon 503demo_unavailable(jamais créé) ; une session ouverte est conservée, une session de démo dure 2 h au plus, sans preuve de connexion récente, et 200 au plus sont gardées ; une même adresse en ouvre 20 au plus par 5 minutes (429), et/api/auth/men’enregistre plus la langue d’interface d’un compte de démo. Un compte de démo administrateur est signalé au démarrage (demo_account_is_admin) (#294). -
API de la liste des premiers pas :
GET /api/onboardingindique à l’administrateur les étapes faites (licence, provider, test de la clé, premier livre, mot de passe initial d’adminchangé) et si un provider a un prix ;PUT /api/onboardingmasque ou réaffiche la liste. Tout est lu localement, rien ne bloque l’application (#283). -
La mention lisible par machine « traduction assistée par IA » des EPUB exportés est activée par défaut et se désactive pour toute l’installation (
PUT /api/settings/exports) ou pour un livre (ai_disclosuredePATCH /api/projects/{pid}/edition, le choix du livre l’emportant) ; le choix vaut pour le téléchargement, le lot, l’API v1, la bibliothèque, WebDAV et le courriel, sans changement de schéma (#284). -
Le formulaire du provider affiche l’entrée disponible par appel (fenêtre − sortie − réserve du format de réponse, réserve envoyée par
GET /api/providers/policydansinput_budget) et avertit sous 48 000 tokens, taille habituelle de la synthèse Book Bible d’une longue série : en dessous, la synthèse ne tient plus en un appel. Les valeurs suivent la fenêtre et la sortie à la saisie (#281). -
Jeux de mots conservés à la traduction : l’analyse des passages relève désormais les jeux de mots, déformations volontaires et quiproquos lexicaux de chaque passage (mots source exacts et effet) ; seuls ces passages sont traduits ou révisés par le modèle supérieur du livre, avec la consigne de recréer l’effet dans la langue cible ou de signaler ce qui est perdu. Chaque bascule est inscrite une fois par passage dans le journal de l’autopilote (
kindwordplay) : les appels au modèle supérieur restent bornés et comptables ; sans modèle supérieur, le modèle du livre reçoit la même consigne. Les prompts intégrés passent enfile-v17(#274).
Corrigé
-
Une traduction restée en alphabet latin pour une langue cible écrite dans sa propre écriture (tamoul, russe, japonais, arabe…) lève désormais l’erreur
untranslated: moins de 20 % de ses lettres dans l’écriture cible, à partir de 20 lettres, pour ne jamais signaler un nom, un numéro de chapitre ni un passage qui cite quelques mots anglais (#317). -
L’assistant d’import demande son estimation de coût avec la langue cible choisie (
target_language) et la redemande quand elle change : un livre vers le tamoul n’est plus estimé avec les valeurs par défaut moyennes (#314). -
Un EPUB exporté dont le document de navigation source n’a pas de
<head>n’est plus refusé par EPUBCheck (RSC-005,OEBPS/nav.xhtml) : la reconstruction ajoute un<head>avec un<title>avant le<body>(#316). -
Un nom plus long que le texte ne dit jamais (« Alice Liddel », lu dans la notice de l’éditeur) n’est plus verrouillé comme rendu de son alias (« Alice ») : un nom du glossaire dont la traduction ne fait qu’ajouter des mots à la source est un autre nom du personnage, pas une traduction, et il est verrouillé sous sa forme source (LIB-619).
-
Une forme d’adresse lue dans la source n’est plus perdue quand sa phrase citée contient un mot en italique (LIB-621) : le contrôle des citations ignore les marqueurs en ligne (
⟦t0⟧…⟦/t0⟧), si bien que la paire Alice/Chenille arrive dans la fiche de style au lieu de laisser au modèle le « vous » par défaut. Les deux prompts de relecture (file-v26) précisent aussi qu’une paire ne vise que deux personnages et qu’un couple sans paire est jugé sur la constance, pas sur une forme supposée : sur un passage, 3 rejeux sur 8 noyaient la relecture sous 6 à 10 faux constats de registre, 2 mineurs restent. -
Typographie française (#310) : l’espace qu’un modèle laisse après une élision est retirée (
qu’ est-ce→qu’est-ce, de mêmel’,jusqu’,aujourd’…), à l’enregistrement comme à l’export. Alice M3 livrait « qu’ est-ce qu’une course collective fantaisiste ? ». Un guillemet ‘…’ fermant garde son espace. -
Avec la politique de noms
keep, un personnage que l’analyse a traduit sous une autre forme (« old Crab » → « Cangrejo viejo », trop rare pour être retenue) n’est plus verrouillé non traduit au glossaire (Crab → Crab) ; les noms propres (Alice, Dinah) restent gardés (#308). -
Un nom que l’autopilote verrouille au glossaire ne porte plus l’article de la langue cible :
Queen→ « la Reine » est verrouillé en « Reine »,King→ « el Rey » en « Rey » ; l’article suit la phrase (« de la Reine », « del Rey »). Un article à majuscule qui fait partie du nom (La Fontaine) reste (#309). -
Bibliothèque et page de série : la pastille d’un volume suit l’état
display_statedu serveur : « Intervention requise » (rouge) quand l’autopilote s’est terminé bloqué, « Points à vérifier » (orange) tant que des passages restent ouverts, « Terminé » seulement sans résidu ; le tri par état et le filtre « À examiner » de la bibliothèque le suivent aussi (#305). -
Analyse des chapitres : une forme d’adresse, une relation, un référent ou un attribut de personnage dont la citation enjambe un retour à la ligne dur de la source (les EPUB Standard Ebooks/Gutenberg coupent les lignes au milieu des phrases) n’est plus écarté parce que le modèle l’a citée sur une ligne ; seuls les espaces sont tolérés, une citation inventée reste rejetée. Dans Alice, les paires Alice/Souris et Alice/Lory atteignent désormais la fiche de style (réf. #303).
-
Contrôle qualité : un guillemet fermant « » » sans ouvrant dans un paragraphe traduit (espagnol, français, italien, portugais, catalan, russe…) est signalé (
orphan_quote, avertissement) quand la source du paragraphe est équilibrée, pour que la relecture et l’autopilote le corrigent. Une réplique d’Alice ouverte par un tiret se terminait par un « » » orphelin sans que rien ne le relève. Les reprises « » » en tête de paragraphe ou de strophe d’une citation poursuivie ne sont pas signalées (#307). -
Import EPUB (découpage 4) : un long texte à nu (paragraphes posés directement dans
<body>, séparés par des lignes vides) est coupé entre ses paragraphes avant de l’être entre ses phrases. Dans l’édition d’essai d’Alice, « However, everything is queer to-day. » ouvrait seule le passage suivant : la traduction fermait la réplique trop tôt et la phrase passait pour un ajout sans source. Les livres déjà importés gardent leur découpage et leurs archives se restaurent à l’identique (#304). -
Typographie (#301) : le
<title>des pages et la table des matières de l’EPUB recopiaient le titre traduit d’un chapitre avec des espaces ordinaires là où il avait des espaces insécables (Chapitre 1 : …avant le deux-points) ; ils les gardent désormais. Un test de non-régression garantit aussi que la typographie française et la reconstruction de l’EPUB n’ajoutent jamais d’espace après une apostrophe ou un ¿/¡/« ouvrant devant un code inline (l’<i>écoute</i>,Qu’<i>est</i>-ce,¿<i>Qué</i>). Les EPUB exportés étaient déjà corrects ; les espaces vues à la notation M2 venaient d’une extraction de texte qui joignait les nœuds XHTML par des espaces. -
Contrôle de fidélité sémantique : la preuve du juge est comparée après normalisation (NFKC, espaces insécables vues comme des espaces, marqueurs
⟦…⟧retirés, espaces multiples réduites) et acceptée si elle est une sous-chaîne de l’unité source. Le juge ne donne plus queunit_idet une courte citation de la source ; le serveur cite lui-même les textes précédent et candidat de l’unité. Une divergence dont la preuve n’est pas vérifiable ne fait plus jeter tout le verdict (invalid_evidence, texte précédent conservé) : les divergences vérifiées refusent toujours le candidat, les autres deviennent un point de relecture « preuve non vérifiable », sans blocage (#300). -
Mettre à jour les composants Jackson d’EPUBCheck en 2.18.11 : cette version corrige CVE-2026-91776 et CVE-2026-91777 (HIGH dans
jackson-databind) signalées par le scan de vulnérabilités des conteneurs (libris/libris#298). -
Le nom d’un personnage dans un titre de chapitre n’est plus signalé comme jeu de mots (libris/libris#295) : « Bill » dans « Chapter 4: The Rabbit Sends in a Little Bill » était lu comme un bec ou une facture (
bill) à l’extraction comme à la réconciliation, et ce faux jeu de mots envoyait le passage au modèle supérieur. Les trois prompts d’analyse (file-v24) écartent désormais un nom sauf si le texte joue sur le mot courant, et l’ancrage écarte un calembour de la ligne de titre dont la seconde lecture est le même mot (cible vide ou même mot à la casse près) ; tale/tail sur la ligne de titre est conservé. -
Verrouillage des noms selon la Book Bible : un nom n’est compté que là où il est écrit avec ses majuscules ; le nom commun (« a duck », « the duck ») ne gonfle plus le compte de « Duck » et un nom peu employé n’est plus verrouillé à tort (#296).
-
Une synthèse de la Book Bible dont la réponse dépasse le budget de sortie du provider (
finish_reason: length, JSON coupé) n’est plus perdue d’un bloc : son entrée est coupée en deux, sur deux niveaux au plus, et seule cette synthèse est redemandée ; les autres ne sont pas refaites. Au-delà, la synthèse est abandonnée comme avant (book_bibledans le journal de l’autopilote). Les autres réponses invalides ne sont pas découpées (#277). -
Une longue série n’affame plus le provider qui la suit : préparer un passage construisait l’URI de chaque événement de la série en relisant les réglages OpenViking (une requête et un déchiffrement de clé par événement, environ 2 000 fois pour un passage d’une série de douze volumes, plus de la moitié de son temps de calcul), puis lisait les fichiers retrouvés l’un après l’autre. La racine de l’espace est lue une fois et les fichiers sont lus ensemble. Sur une série synthétique de douze volumes avec un OpenViking à 150 ms et un provider Qwen à 10 places, un passage est préparé en 0,7 s au lieu de 3,1 s (0,55 s de calcul au lieu de 1,8 s), le modèle reçoit en moyenne 9,0 requêtes à la fois au lieu de 3,3, et le worker consomme 34 % d’un cœur. Le journal du travail indique maintenant, à chaque départ de passage, le délai depuis le précédent, la largeur effective (
job_parallelism) et les passages en cours (parallel=start gap=… width=… in_flight=…) (#293). -
Une synthèse de la Book Bible encore trop grande pour le provider une fois découpée par sa structure (nouveaux chapitres rejoignant une bible existante, ou fusion de l’arbre) est désormais reconstruite à partir des synthèses de ses deux moitiés de chapitres, fusionnées l’une après l’autre, jusqu’au chapitre seul, avant de bloquer le livre ; l’arrêt explicite
book_bible_context_too_largereste si même cela ne tient pas (#281). -
Un titre de chapitre en première ligne d’un passage TXT ou DOCX, fusionné avec le premier paragraphe, est désormais examiné pour les jeux de mots comme toute autre proposition : les trois prompts d’analyse disent que, quand TARGET_TEXT s’ouvre sur un titre de chapitre, son jeu compte et sa source est la ligne du titre. Mesuré sur Luna sur le passage fusionné « Chapter 3: A Caucus-Race and a Long Tale », tale/tail est listé dans 3 rejeux d’extraction sur 4 (1 sur 4 avant) et dans 3 rejeux de réconciliation sur 3 (1 sur 3 avant). Le découpage ne change pas. Les prompts intégrés passent en
file-v23(#291).
Tests
- Vérifier que chaque motif de correction refusée par l’autopilote a une traduction anglaise (#268).
- Synchroniser le test mobile de l’export bilingue sur les réponses mockées de session et de projet avant de vérifier l’écran.
- Le test du budget de raisonnement d’un provider remplace
llm.modelssur l’instance : après le monkeypatch d’un autre test, un attribut d’instance masquait le remplacement de classe et le test appelait pour de vraihttps://1.1.1.1/v1/models(HTTP 301 surbackend-postgres, pipeline 4172 ; #318).
Corrigé
- L’analyse parallèle (
ANALYSIS_MODE=parallel, le mode par défaut) apprend désormais les formes d’adresse par paire de personnages : les prompts d’extraction et de réconciliation les demandent, et une réconciliation qui les omet garde celles de l’extraction. Promptsfile-v22(#279). - Deux mots qui se prononcent de même et qu’un qualificatif permet de lire des deux façons (« A Caucus-Race and a Long Tale ») sont désormais listés comme jeu de mots, même dans un titre de chapitre : l’extraction notait tale/tail dans
style_notesseulement, puis la réconciliation abandonnait le jeu, si bien que le titre partait sur le modèle du livre sans note. La consigne figure dans les trois prompts d’analyse ; mesuré sur Luna, le titre donne le jeu dans 3 rejeux sur 4 (0 sur 5 avant) et la réconciliation garde un jeu extrait (2 sur 2, 0 sur 2 avant), sans jeu ajouté sur les cinq passages témoins. Les prompts intégrés passent enfile-v21(#280). - Les exports TXT et Markdown d’un chapitre EPUB en texte nu posé directement dans
<body>(paragraphes séparés seulement par des lignes vides) gardent chaque paragraphe sur sa ligne, séparé par une ligne vide, comme l’export EPUB ; tout le chapitre sortait auparavant sur une seule ligne (#276). - Les jeux de mots relevés à l’analyse ne se perdent plus quand la citation du modèle dérive : chaque jeu nomme désormais le mot source sur lequel il repose (
word) et le mot qu’il vise (target, par exemple tale → tail) ; il est conservé dès que ce mot est dans le passage, même si la citation porte des guillemets ou une ellipse. Les prompts d’analyse définissent le jeu de mots par la forme des mots source (double sens, mots proches à l’oreille, déformation, quiproquo lexical) ; la consigne envoyée avec un passage signalé garde visiblement fautif un mot volontairement faux dans la langue cible et demande une note du traducteur préfixéewordplay:quand aucun équivalent n’existe. Les prompts intégrés passent enfile-v18(#274). - Les noms de personnages suivent la politique des noms de la Book Bible : l’analyse du livre dit si les noms et noms-titres (le Lapin Blanc, le Canard) sont gardés ou traduits (
name_policy), l’analyse des chapitres les propose comme termesname, et l’autopilote verrouille chaque nom accepté employé au moins aussi souvent que l’exigeAUTOPILOT_GLOSSARY_MIN_CONFIDENCE, dans sa forme d’origine quand les noms sont gardés ; un nom-titre employé sans article (« Duck said ») compte aussi, et un lot d’analyse suivant sans politique garde celle déjà décidée. Un terme écrit ou corrigé par une personne n’est jamais réécrit ni verrouillé. Un nom verrouillé garde aussi ses majuscules au contrôle de la traduction (« el Pato », pas « el pato ») ; les autres termes verrouillés ignorent toujours la casse. Les prompts intégrés passent enfile-v20(#275). - Les noms gardés par la Book Bible sont verrouillés même quand l’analyse ne les cite que comme personnages, pas comme termes du glossaire : avec
keep, chaque personnage assez souvent nommé entre au glossaire sous sa forme source et y est verrouillé ; un terme décidé par une personne reste intact. Sur Alice, GPT-6 Luna ne proposait aucun nom comme terme et rien n’était verrouillé (#275). - Les noms traduits par la Book Bible sont aussi verrouillés quand l’analyse nomme un personnage dans la langue cible et garde sa forme source en alias (« Canard », alias « Duck ») : avec
translate, cette forme source entre au glossaire avec la traduction de l’analyse et y est verrouillée si le livre l’emploie assez souvent. Un personnage encore nommé dans sa forme source ne reçoit aucune traduction inventée (#275). - Export EPUB : la ligne vide entre deux paragraphes est conservée quand un long chapitre a été coupé en deux parties à cet endroit ; le dernier paragraphe d’une partie et le premier de la suivante restent deux
<p>au lieu d’un seul (#272). - Export EPUB : un chapitre dont le texte est posé directement dans
<body>(ou une<div>), avec des paragraphes séparés seulement par des lignes vides, est exporté avec un<p>par paragraphe ; ses paragraphes et répliques ne fusionnent plus à l’affichage (#271). - La page d’un livre ne garde plus l’alerte générique « Failed to fetch » une fois ses données relues : une actualisation du livre qui échoue (projet, sections, travaux) s’affiche désormais sur le livre avec un bouton pour réessayer, et disparaît à la prochaine actualisation réussie ; un livre dont le premier chargement échoue propose la même reprise au lieu de charger sans fin (#270).
- Un document de navigation EPUB 3 (
nav.xhtml) ou un NCX déclaré dans le manifeste mais absent du spine n’est plus importé comme une section à traduire : seuls les documents du spine sont découpés en passages, et l’export réécrit toujours le sommaire à partir des titres traduits. Les nouveaux imports utilisent le découpage 3 ; les livres et archives découpés avant gardent leurs sections (#269). - Compiler une seule fois le motif de chaque nom de la série quand les passages construisent leur contexte en parallèle : une analyse relancée sur un worker à froid faisait compiler les mêmes noms par dix fils, et sa première requête au modèle, comme les autres travaux du worker, attendait environ deux fois plus longtemps (LIB-329).
- L’autopilote ne refait plus l’arbitrage d’un passage reporté quand son texte, ses critiques, ses points ouverts et son modèle sont inchangés et qu’aucun modèle supérieur n’est configuré : la même question recevait le même refus à chaque tour (environ 1 h 30 par livre). Le passage garde son motif dans le rapport final ; une entrée modifiée ou un modèle supérieur rouvre l’arbitrage (#267).
- Ouvrir un gros chapitre dans l’éditeur en environ une seconde au lieu de deux et demie : chaque champ de traduction était mesuré par un script (un recalcul de mise en page forcé par unité, quadratique sur une page de 50 passages) ; le miroir qui dessine les codes de mise en forme dimensionne désormais le champ par le seul CSS (LIB-330).
- Une analyse relancée envoie sa première requête dès que son premier contexte est prêt : un travail prépare désormais ses contextes un par un, dans l’ordre, au lieu de tous ensemble ; les autres travaux n’attendent pas. Une recherche OpenViking bloquée est coupée après 10 s et le contexte se replie sur la base de données (#264).
Modifié
- Les motifs de noms construits avec
word_boundariesne sont compilés qu’une fois (lru_cacheborné dansengines/word_boundary.py) dans les contrôles qualité, l’édition, la recherche en mémoire et la propagation, au lieu de l’être à chaque passage (#265).
Sécurité
- PyJWT 2.15.0 (GHSA-42vr-xj54-vc7v) : l’audit des dépendances refusait la 2.14.0 et bloquait
main.
Corrigé
- Un poème envoyé en JSON ou en TXT garde ses lignes : un bloc séparé par des lignes vides d’au moins trois lignes courtes commençant par une majuscule (ni dialogue, ni prose coupée, ni liste « Nom : valeur ») devient une seule unité avec ses retours à la ligne ; il est donc reconnu comme vers et confié au modèle supérieur. Avant, ses lignes étaient recollées par des espaces (Crocodile) ou chacune un paragraphe (Jabberwocky). Les exports texte et EPUB rendent les lignes, l’export Word en sauts de ligne. Les chapitres importés avant gardent leur découpage et leurs archives de projet se restaurent à l’identique (
layout.version2) (#312).
[0.25.0] - 2026-09-29
Notes de mise à jour
- Une migration,
2b4e91c7d605, remet àokles anciens passageschecksans motif de relecture restant. Les passages avec un point qualité ouvert, une critique, une incertitude ou une erreur restent à relire. Aucun changement du protocole de licence ; compatible avec le serveur 0.12.3 déployé.
Tests
- Couvrir la boucle complète de l’autopilote avec plusieurs suggestions d’erreur, le refus d’une suggestion contraire à un terme verrouillé et un résidu motivé.
Modifié
- Sérialiser séparément les suites CI backend SQLite et PostgreSQL entre les pipelines de MR, tout en laissant les pipelines de
mainpasser sans attendre dans ces files (#245).
Corrigé
-
À la migration de la base, remettre à
okles anciens passageschecksans critique, incertitude, erreur ni point qualité ouvert ; conserver les passages ayant une raison de relecture et ceux déjà validés. -
Revérifier les suggestions de critiques retenues par l’autopilote avant de clore une erreur : si la seconde lecture retrouve cette erreur, conserver la traduction précédente et renvoyer la proposition à l’arbitrage. Le rapport de fin compte les suggestions appliquées, rejetées et encore ouvertes, et motive chaque passage laissé à vérifier après les tours bornés.
-
Les modifications de personnages, de glossaire et de formulations adoptées ne signalent plus que les passages concernés. Chaque revérification en attente garde un point qualité lisible ; une revue finale ciblée est mise en file, puis efface le signalement ou laisse un point motivé. Une décision prise pendant la revue reste en attente d’un nouveau passage. Les autres changements de fiche de style avancent seulement la révision de la mémoire.
-
Un rapport de pilote automatique bloqué est recompté sur l’état actuel des passages : une fois les passages listés corrigés ou validés à la main, le rapport, l’état du livre et le menu Exporter ne disent plus « bloqué » et l’EPUB traduit est de nouveau proposé (#262).
-
La revue finale du pilote automatique n’échoue plus en « base de données indisponible » (
ArgumentError) pour un travail dont les options portentsegment_ids: null; elle relit de nouveau tout le périmètre (#261). -
La ligne d’état « Pilote automatique bloqué » de la fiche livre affiche les tours de convergence, le motif et l’action requise sur des lignes séparées au lieu d’une phrase collée (#259).
-
Mettre à jour les composants Jackson d’EPUBCheck en 2.18.10 : cette version corrige CVE-2026-68497 et le scan de vulnérabilités des conteneurs.
-
Un livre dont le dernier passage du pilote s’est terminé bloqué n’affiche plus « Livre prêt à exporter » dans l’étape Export ni dans la bibliothèque : l’avancement porte désormais
autopilot_outcome(#260). -
Relecture finale : un passage dont le contexte complet dépasse la fenêtre du fournisseur (passage et critiques précédentes trop longs, ou plus de place pour le voisinage) est désormais relu dans le contexte réduit qu’utilisait déjà l’arbitrage : le passage, ses règles obligatoires, sa traduction actuelle et la mémoire qu’il nomme, puis autant de critiques précédentes que la place le permet. Huit passages d’une fenêtre de 32 768 jetons échouaient trois fois sur le même
ContextTooLargesans jamais conclure. Si même le passage et ses règles dépassent la fenêtre, la relecture le signale une fois et n’est pas relancée (#256). -
Pilote automatique : un livre dont les tours bornés s’achèvent avec des passages encore dans la langue d’origine, des points de relecture ouverts ou des contrôles non concluants se termine désormais
blocked(« Bloqué · pas prêt à exporter ») avec les nombres exacts (source_passages,unresolved_passages,unverified_checks), au lieu de « Terminé » avec un téléchargement ; un livre sans résidu reste prêt. Un séparateur de scène (* * *) n’est plus signalé comme du texte resté dans la langue d’origine, et une révision écrite au dernier tour reçoit son contrôle par le juge qualité au lieu d’arriver au rapport sans aucune tentative. Les requêtes de l’API se terminent toujours encompleted_with_residuals(#255). -
Pilote automatique, livre bloqué : la ligne d’état et le rapport disent quoi faire (ouvrir le rapport et traiter les passages), et le menu Exporter nomme l’EPUB « EPUB provisoire · livre bloqué » ; il reste téléchargeable mais n’est plus présenté comme le livre terminé (#255).
-
La préparation d’un passage d’une longue série est environ trois fois plus rapide : son texte n’est converti en demi-chasse que s’il contient un caractère pleine chasse, au lieu d’une fois par nom connu de la série (tome précédé de 18 autres : 18 s → 6 s de calcul par passage) (#253).
-
Les motifs d’un passage à revérifier après plusieurs changements de mémoire (par exemple un personnage et un terme du glossaire) s’affichent tous en anglais dans l’interface anglaise ; le texte français stocké ne change pas (#250).
-
Qualité : les points de revérification laissés par un changement de mémoire ou de style affichent un intitulé lisible et traduit au lieu du code brut
memory_changed/style_changed(#250). -
Qualité : un terme verrouillé absent affiche un intitulé lisible au lieu du code brut
locked_term, et son motif (« Traduction verrouillée absente : … ») s’affiche en anglais dans l’interface anglaise ; les constats des contrôles stockés sous la forme<passage> : <motif>sont traduits après l’identifiant du passage (#252). -
Qualité et relecture : les motifs des points et des problèmes passent dans la nouvelle langue de l’interface en même temps que leurs intitulés, sans recharger la page (#251).
-
Worker : les travaux en cours ne perdent plus leur bail et ne redémarrent plus en boucle pendant la reconstruction du catalogue de mémoire. Cette passe sur tous les livres, qui durait plusieurs minutes pendant la préparation des passages, tourne désormais hors de la boucle d’événements, et un travail repris après expiration de son bail est journalisé (
status=reclaimed) (#253). -
Worker : un travail dont l’exécution est toujours vivante n’est plus repris quand son processus reste figé plus longtemps qu’un bail (hôte saturé, conteneur gelé). La boucle du même processus reprenait le travail avant le battement de cœur, jetait l’appel au fournisseur en cours et relançait le travail (
status=reclaimed, tentatives 8 → 9). Une exécution vivante dans le processus renouvelle désormais son bail et garde son travail jusqu’à 10 minutes après l’expiration ; une exécution qui ne renouvelle plus rien au-delà, ou le travail d’un processus mort, est reprise comme avant. Un renouvellement tardif de plus de 40 s est journalisé (heartbeat=late) (#254). -
Provider ChatGPT (Codex) : la vérification des modèles renvoie la fenêtre de contexte de chaque modèle lue dans le catalogue Codex (
context_windows, 272 000 jetons pour GPT-6 Luna et Sol), pour que le formulaire ne garde plus le défaut de 32 768 ; un modèle absent du catalogue, ou un catalogue illisible, est simplement omis et les autres providers ne changent pas (#257). -
Provider ChatGPT (Codex) : le formulaire préremplit la fenêtre de contexte avec celle du catalogue pour le modèle détecté ou choisi (272 000 pour GPT-6 Luna et Sol) tant que le provider n’a pas encore de modèle enregistré ; une fenêtre saisie à la main ou déjà enregistrée n’est jamais écrasée (#257).
[0.24.0] - 2026-09-28
Notes de mise à jour
- Une migration,
73c9e2a14d60, ajoutellm_requests.imported(faux pour les requêtes existantes). Aucun changement du protocole de licence ; compatible avec le serveur 0.12.3 déployé. Cette version regroupe les corrections de l’audit 0.23.0 (#237), les correctifs de sauvegarde et de restauration (#243, #244) et le travail préparé sous le nom 0.23.1, jamais tagué. - Les traductions et réécritures passent désormais un contrôle indépendant de fidélité sémantique : un appel
de modèle de plus, sur le provider du travail, pour chaque passage traduit ou réécrit. Si ce contrôle ne peut
pas s’exécuter ou relève une divergence, la candidate est refusée, le texte antérieur reste et un point de
revue humaine s’ouvre : prévoir davantage de points de revue quand un provider est indisponible. Les prompts
intégrés passent à
file-v16+rules-v7; un prompt enregistré par un administrateur dans Paramètres › Prompts garde son propre texte. - Installations du registre : relancer l’installateur (
LIBRIS_TAG=0.24.0) plutôt que tirer les images, pour installer à côté de Compose les outils de sauvegarde et de restauration livrés dans l’image.
Modifié
- L’interface suit la charte graphique commune avec le site : titres et nom de marque en EB Garamond
(romain seulement) et interface en Schibsted Grotesk, à la place de Fraunces et d’Inter ; Source
Serif 4 compose toujours les livres, leur italique compris. L’interface ne pose plus d’italique
(rubrique de connexion et libellés de preuves de série en romain), les titres perdent l’espacement
des mots qu’exigeait Fraunces et les titres de carte passent à 18 px. Les lignes de l’assistant
d’import et les prochaines actions d’une série portent leur état sur tout leur filet au lieu d’une
bande latérale de 3 px ; citations, preuves et propositions de l’IA prennent un filet de 1 px ; un
personnage validé est entouré au lieu d’être rayé ; les états vides et la revue finale IA montrent
leur icône sans tuile. En mouvement réduit, les retours de couleur et de focus restent, seuls les
déplacements s’arrêtent.
libris-logo.pnggarde l’illustration du propriétaire et compose « Libris » en EB Garamond, et les captures de la documentation sont régénérées.
Ajouté
-
Un rapport avant/après reproductible du moteur de traduction réel sur le corpus annoté, avec coûts des modèles, comptes de confusion et manifestes des exécutions archivés.
-
Vérifier les dialogues anglais, les règles des prompts et le maintien d’un choix humain dans l’autopilot complet, pour des sources françaises et chinoises.
-
Le titre canonique cible d’un livre, ainsi que le titre propre d’un chapitre après édition, parviennent désormais à la traduction et aux passes de réécriture comme terminologie de haute priorité (
backend/app/engines/context/canonical_title.py),context.builder._prepareet le contexte réduit d’une reprise de passage compris. Seule une décision éditoriale explicite (titleouchaptersde l’édition manuelle) rattache un titre cible à la forme source qu’il traduit — jamais une ressemblance supposée ; deux décisions traduisant différemment la même forme source n’injectent aucune contrainte plutôt qu’une instruction contradictoire. Un terme de glossaire verrouillé ou une décision de série déjà en vigueur pour cette forme source continue de l’emporter. Confirmée seulement dans le passage lui-même, jamais un voisin affiché autour pour la continuité, et seulement pour les mots exacts du titre — un mot ou une expression ordinaire qui titre un livre ou un chapitre est assez courant ailleurs pour qu’une occurrence voisine ou fléchie (un pluriel, une forme déclinée) ne soit qu’une supposition, pas une référence confirmée. Une décision personnelle sur cette forme source, même restée non verrouillée (import de glossaire, correction manuelle), l’emporte de la même façon ; une forme source qu’un personnage du livre porte déjà (homonyme de même casse compris) offre une correspondance trop incertaine pour être rattachée au titre et n’injecte donc aucune contrainte. Partie 1 de libris/libris#242 : l’harmonisation du titre entre l’OPF, la navigation, les intitulés et les exports, ainsi que le signalement d’une divergence persistante, fait l’objet de la partie 2. -
Contrat du vérificateur de fidélité sémantique : schémas
FidelityDivergence/FidelityVerdictetprompts/fidelity_check.txtdéfinissent un contrôle indépendant — relisant la source, la version précédente et la candidate, jamais l’autoévaluation de la passe qui l’a produite — pour sept catégories d’assertions contrôlées (négation, agent/action/patient, résultat d’action, nombres et portée, identité/état d’objet, blessure/décès, noms de techniques ou termes culturels). Un corpus synthétique multilingue de 21 cas (backend/tests/fixtures/fidelity_corpus.yaml, FR/EN/ZH/JA) couvre les cinq fautes de l’issue GitLab libris/libris#241, des reformulations fidèles, des contradictions intentionnelles de la source et des décisions humaines déjà tranchées. Un contrôle indépendant relit désormais la traduction initiale et chaque candidate de révision, polissage, relecture fusionnée ou finale, correction qualité et arbitrage. Une candidate divergente est refusée, le texte antérieur et un point de revue sont conservés. Le rapport distingue contrôle sans divergence, divergence et contrôle non exécuté.
Corrigé
-
Contrôle des guillemets de dialogue limité aux répliques identifiées. Les titres, noms de technique et mots cités ne créent plus de faux constats ; une citation incertaine reste un avertissement faible à examiner, sans déclencher de réécriture automatique des noms, citations ou locuteurs. Avec des dialogues en tirets, les pensées et lettres entre guillemets typographiques restent intactes.
-
Une correction du titre canonique se retrouve dans les EPUB reconstruits et bilingues ainsi que dans les exports texte. Les passages machine dont la correspondance est sûre suivent le nouveau titre ; le texte validé et les décisions éditoriales ou de série concurrentes restent intacts. Les homonymes ordinaires en langue cible et les collisions entre titres de livre et de chapitre restent à relire. Les divergences figurent dans les contrôles qualité existants avant l’export ou la publication, sans rouvrir un avertissement déjà résolu par l’éditeur.
-
Affichage du nombre de passages ignorés et du motif de validation pour chaque échec de propagation du glossaire dans l’interface du livre.
-
Recherche des termes du glossaire dans la source quelle que soit la chasse des lettres latines, pour le contexte, les contrôles et la propagation, avec des positions fidèles au texte d’origine.
-
La fiche de style ne propose et n’applique plus que des valeurs que la grammaire et la typographie de la langue cible possèdent réellement : aucune règle tutoiement/vouvoiement pour une cible anglaise, aucune règle de guillemets français pour une cible dont la convention est le tiret, le passé composé réservé aux langues où il forme un registre à part (français, italien). Une décision de la série héritée par un volume dont la cible ne la partage pas n’est plus reprise — y compris la forme tutoiement/vouvoiement d’un couple — tandis que la décision explicite d’un volume, et tout couple qu’il fixe lui-même, ne sont jamais touchés. Une proposition « fidèle » comme « atténué » pour les gros mots exige désormais une grossièreté effectivement citée dans sa preuve, côté code comme dans le prompt, sous peine d’une confiance basse.
-
La consolidation de la Book Bible ne dépasse plus la fenêtre du provider quand une seule synthèse entrante fusionne avec une Bible existante : le registre de personnages envoyé se limite aux identités citées dans la Bible de base ou le fragment courant, et un élément unique trop grand est découpé par structure (ses listes, par moitiés) plutôt que d’être abandonné en entier. Si même le plus petit fragment ne tient pas à côté de la Bible existante, la taille requise, le budget et la fenêtre sont signalés explicitement, aucune section n’est faussement marquée consolidée, et le point de reprise garde cette taille pour qu’une reprise avec le même provider et la même fenêtre ne relance pas la même synthèse à l’identique. Une reprise avec un autre provider ou une fenêtre plus large relance désormais les synthèses qu’une tentative précédente avait abandonnées, au lieu de les laisser abandonnées pour toujours (#238).
-
Refus d’une traduction ou réécriture lorsque le contrôle sémantique indépendant ne peut aboutir ou cite une preuve non concordante ; conservation du texte antérieur et ouverture d’un point de revue humaine.
-
Les outils de sauvegarde et de restauration voyagent dans l’image du registre et sont installés avec Compose ; un
.envsauvegardé est conservé pour une restauration neuve, et--no-startévite tout démarrage avant la remise de la base et des livres. -
Sérialisation des corrections automatiques entre tomes et suppression des anciens termes importés d’une autre paire de langues, sans toucher aux termes manuels.
-
Conservation des décisions d’arbitrage acceptées sans changement de texte, traduction du nombre de corrections de série et reprise des propositions acceptées après le dernier élément traité.
-
Réécriture possible d’une traduction dont un appel de note manquait déjà, y compris après acceptation d’une proposition ; signalement des passages écartés de la propagation du glossaire et conservation des alertes qualité résolues.
-
Un volume qui passe à une autre paire de langues — requête d’automatisation, EPUB renvoyé, réglages du volume ou langue de la série — ne garde plus les valeurs de style devinées par l’autopilote pour la précédente paire source→cible : elles sont écartées et la fiche de style redemandée pour la nouvelle paire, tandis qu’un choix de style fait par une personne reste inchangé, même quand la fiche de style le réécrit avec la même valeur que celle devinée par l’autopilote.
-
La restauration d’une archive ne supprime plus les statistiques d’un livre effacé désigné par l’archive. Les requêtes restaurées sont marquées comme historique importé et ne comptent jamais comme nouvelle dépense, y compris pour le plafond quotidien. Une preuve de provenance signée pour cette installation, le propriétaire initial et le contenu complet de l’archive autorise la réattribution des agrégats du livre source supprimé ; les archives sans preuve ou avec l’ancienne preuve restent restaurables sans modifier les agrégats. La migration
73c9e2a14d60ajoutellm_requests.imported(faux pour les requêtes existantes). -
Les préquelles repérées
Vol. 0ouVol. 0.5précèdent désormais le volume 1 dans l’ordre de lecture, la mémoire de série et la position EPUB. L’assistant d’import ne propose plus le numéro 0 invalide à partir d’un nom de fichier. -
Relance ou repli contrôlé après une réparation ciblée invalide, et vérification des termes verrouillés même dans une réponse partielle.
-
Achèvement des passages modifiés automatiquement, exclusion des relectures et travaux ciblés de la garde de consolidation globale, et effacement d’un ancien échec de fenêtre de Book Bible à la reprise.
-
Poursuite de la traduction si le rafraîchissement narratif facultatif échoue, et motif fidèle pour un polissage refusé à cause d’avertissements ajoutés.
-
Recollement d’un paragraphe TXT de deux lignes coupé vers 70 colonnes, sans faux titre au découpage.
-
Conservation des appels de note portés par un titre DOCX retiré lors du découpage API.
-
Lecture du front matter YAML avec commentaires et clés entre guillemets ou contenant des espaces.
-
Erreur explicite si la couverture traduite manque ou est altérée lors d’un export ou aperçu EPUB.
-
Reconnaissance de suffixes courants des noms coréens sans confusion avec des noms plus longs.
[0.23.0] - 2026-09-27
Modifié
-
La synthèse de la Book Bible fractionne les fusions selon la fenêtre du provider. Le pilote bloque la traduction si des sections restent non consolidées et expose leurs identifiants dans l’API du travail. La page du livre nomme les sections concernées, propose de relancer la consolidation et demande une confirmation explicite avant de reprendre la traduction avec
allow_unconsolidated=truemalgré le risque pour la cohérence. -
L’arbitrage automatique revérifie les constats automatiques et demande une nouvelle relecture sémantique du passage fusionné avant d’appliquer une correction. Une correction refusée conserve les points ouverts pour le tour suivant ; chaque nouvelle révision suit les obligations de relecture.
-
Le polissage, la relecture fusionnée, la relecture finale et le juge qualité partagent une règle d’acceptation fondée sur les constats : les défauts préexistants restent ouverts, une correction partielle peut être conservée et une nouvelle erreur grave fait refuser la réécriture même si le nombre total de constats diminue.
Notes de mise à jour
- Trois migrations :
3b8d51f0c7a2retire la clé étrangère deusage_daily.project_id;8e2f64c1d9b5compte les mots de chaque passage existant (quelques secondes pour une grande bibliothèque) ;4cc7ed91a205ajoute les choix d’édition du livre (projects.edition, vide par défaut). Aucun changement du protocole de licence : fonctionne avec le serveur de licences déjà déployé (0.12.x).
Ajouté
-
Un corpus d’évaluation court et annoté à la main pour la qualité des traductions (
backend/eval/corpus, voirdocs/evaluations/corpus.md). Neuf cas, trois paires de langues (anglais→français, japonais→anglais, chinois→anglais) et quatre formats (EPUB, DOCX, TXT, Markdown) avec 46 annotations couvrant la fidélité, la qualité de langue cible, la cohérence entre chapitres et la dimension EPUB : ellipses, attributs établis, révélations tardives, adaptations légitimes, contradictions intentionnelles, défauts propres à la source et erreurs avérées, chacune appariée à un témoin pour vérifier qu’un juge ne se contente pas de repérer les vraies erreurs mais évite aussi les faux positifs.backend/tests/test_eval_corpus.pyvalide le schéma et le seuil global (≥ 40 annotations, ≥ 4 par catégorie, ≥ 1/3 de témoins). Exécuter le moteur sur ce corpus et noter le résultat est un travail distinct, à venir (libris/libris#199). -
Choix d’édition du livre. La page du livre permet de modifier le titre publié, la langue, les titres des chapitres, le choix de couverture, son texte alternatif et, au besoin, l’image traduite via l’API d’édition commune. Elle affiche l’image enregistrée par son URL protégée et les erreurs de validation dans l’éditeur.
-
Banc d’évaluation du moteur réel. Une commande avec plafond de coût importe les cas annotés, exécute la traduction et EPUBCheck, conserve les contextes et preuves, mesure les résultats et compare deux exécutions dans un tableau Markdown.
-
Nombre de mots de chaque livre et de chaque série. Les cartes et la liste de la bibliothèque, la page du livre et la page de la série (volume par volume, et au total) affichent les mots de la source, comptés exactement comme la licence les compte (une suite de caractères japonais ou chinois vaut un mot pour deux caractères). Le compte est gardé avec chaque passage et suit un chapitre remplacé ; le total d’une série laisse de côté les volumes archivés, comme ses autres totaux. La carte Réglages › Livre affiche ce même chiffre à jour au lieu de celui noté à l’import.
Corrigé
-
Les événements narratifs d’un passage traduit sont de nouveau conservés quand la typographie de la langue cible modifie son texte (apostrophe française, espace insécable avant
?) : ils étaient écartés, et les passages suivants perdaient ce qui venait de se passer dans l’histoire. -
Un passage récupéré dont la validation finale échoue à l’enregistrement essaie désormais l’échelon de récupération suivant ; le travail poursuit les autres passages et signale les éventuels résidus (#201).
-
Le test de régression des termes coréens verrouillés utilise désormais un nom propre sans ambiguïté, pour vérifier que l’absence d’une traduction obligatoire bloque sans contredire le cas des homographes en début de phrase.
-
L’import TXT et le découpage en chapitres décident du recollage bloc par bloc : les lignes courtes des fenêtres de statut et des strophes restent distinctes, même à côté de prose réellement coupée, y compris dans des blocs répétés de deux lignes (#218).
-
Un refus du fournisseur pendant le contrôle de cohérence du livre bloque désormais le travail au niveau du livre, sans marquer comme refusé le dernier passage traduit avec succès.
-
Les termes allemands verrouillés acceptent désormais la déclinaison faible de l’adjectif après un article, par exemple « Schwarzer Ritter » dans « der Schwarze Ritter » ou « des Schwarzen Ritters ».
-
Les termes verrouillés coréens restent composés après la suppression des accents : leurs particules et terminaisons accolées sont acceptées lors de la traduction et du contrôle de cohérence des séries.
-
Le glossaire de série ne reprend que les termes des volumes dont la paire de langues correspond à celle de la série. Un terme verrouillé dans une autre langue ne remplace plus le terme de série et ne crée plus de faux constat de cohérence (#227).
-
Les contrôles de qualité refusent un paragraphe recopié dans un autre lorsque la source ne contient pas cette répétition. Le polissage et la reprise du juge refusent une phrase déplacée au lieu de la rétablir deux fois (#231).
-
Les noms coréens verrouillés ne sont désormais reconnus que seuls ou suivis de particules et copules coréennes, y compris enchaînées. Un nom au début d’un mot plus long ne bloque plus une traduction correcte (#211).
-
Les termes du glossaire et les noms en lettres latines accolés à du japonais, du chinois ou du coréen sont désormais pris en compte dans le contexte de traduction, les contrôles source et cible, le comptage du pilote automatique et la propagation des termes.
-
Les événements narratifs suivent désormais la révision de la traduction enregistrée. Une réécriture invalide les anciens événements dans le contexte du chapitre et la mémoire SQL/OpenViking ; ils sont reconstruits au prochain besoin. Les retouches typographiques les conservent et l’analyse de la source reste intacte.
-
La traduction et la révision relancent ensemble les paragraphes manquants ou vides en conservant les paragraphes valides, appariés par identifiant unique et remis dans l’ordre de la source. Les paragraphes ajoutés ou désordonnés sont traités si l’appariement est sûr ; les identifiants répétés et l’épuisement des relances ciblées gardent la réparation complète existante.
-
Une proposition acceptée pendant la fin du travail de file maintient désormais ce travail en attente jusqu’à son traitement, au lieu de rester indéfiniment marquée « En attente de l’IA ».
-
Le plafond de correction du juge qualité porte désormais sur les seuls passages traduits par le travail. Les passages déjà terminés n’augmentent plus les 25 % autorisés pour un travail de suite ; cette base reste fixe si le travail reprend après une interruption.
-
L’import Markdown retire la barre oblique inverse d’un saut de ligne forcé quand la ligne suivante appartient au même paragraphe, sans modifier les caractères échappés ni les barres littérales.
-
Les exports de lecture d’un EPUB (TXT, Markdown, EPUB bilingue et intervalles de chapitres) gardent à leur place le code, le texte préformaté et les autres éléments laissés en original.
-
L’import HTML et DOCX écarte les lectures ruby au lieu de les coller au texte de base. L’import DOCX ignore aussi l’ancienne position des déplacements suivis et ne lit le texte qu’à sa nouvelle place.
-
Les propositions éditoriales acceptées relancent les contrôles automatiques sur le paragraphe enregistré avant le calcul du statut. Un texte resté en langue source est signalé, et une alerte de fragment non traduit disparaît après sa correction.
-
Les titres de chapitre EPUB coupés par
<br/>gardent une espace dans le nom du chapitre, les exports texte, le sommaire et le titre du document EPUB traduit. Le titre traduit n’apparaît qu’une fois dans les exports texte. -
Les termes verrouillés capitalisés dans un passage en capitales suivent désormais la même règle de correspondance dans le prompt et le contrôle qualité, y compris lorsqu’un terme court est imbriqué.
-
L’import DOCX conserve les notes de bas de page et de fin : leurs appels numérotés restent dans le texte, et leur contenu à traduire est placé en fin de chapitre avec un avertissement. L’export Word les restitue sous forme de paragraphes ordinaires.
-
Une correction humaine ou la décision de conserver l’original prise pendant un appel au modèle garde désormais son statut et ses alertes à la fin du passage. Le décompte de reprise exclut les passages que la reprise ne peut pas sélectionner.
-
Un chapitre Markdown qui commence par un filet conserve désormais sa première scène ; seuls les blocs de métadonnées avec des clés, y compris des listes YAML, sont retirés.
-
Le contrôle qualité vérifie désormais qu’un appel de note
[3]importé d’un DOCX reste dans la traduction. Ce texte est ordinaire, à la différence des marqueurs immuables de l’EPUB : sans ce contrôle, un appel disparu du corps ou d’une note passait inaperçu. La vérification porte sur le multiset des appels par unité (corps comme note) et ne signale que ceux du texte source qui manquent ; un appel que la traduction ajoute sans équivalent dans la source n’est pas concerné. -
Les parties traduites des longs paragraphes sont recollées avec l’espacement des phrases de la langue cible dans les EPUB reconstruits et les exports texte. Les phrases thaïes et laotiennes gardent aussi leur espace ; le japonais et le chinois restent sans espace.
-
La typographie française conserve une seule fois un code inline ou une paire de codes cités seuls entre guillemets. L’enregistrement d’une traduction valide et la lecture des anciennes traductions ne doublent plus ces marqueurs EPUB (#217).
-
La correction retenue par le juge qualité conserve les points de relecture des paragraphes qu’elle n’a pas réécrits. Le passage reste « À vérifier » s’il en reste ; les points des paragraphes réécrits sont retirés.
-
Une partie de traduction gardée n’est réutilisée après une relance que si son texte source garde le même découpage, ce qui évite les phrases répétées ou manquantes quand la fenêtre change.
-
L’import d’un TBX multilingue ignore une entrée sans langue source ou cible quand cette langue est présente ailleurs dans le fichier, au lieu d’importer un terme d’une autre langue étiquetée. Le repli par position reste disponible pour les sections sans langue et les fichiers sans langue correspondante.
-
L’export Word reprend désormais le texte de lecture des chapitres EPUB et TXT : les codes de mise en forme et les métadonnées ne sont plus visibles, chaque paragraphe du livre devient un paragraphe Word et le titre traduit du chapitre n’apparaît qu’une fois. Les corrections suivies et les commentaires de doute restent ancrés sur les paragraphes concernés.
-
Les erreurs de marqueurs EPUB ne relancent que les paragraphes concernés pendant la traduction, la révision et l’arbitrage automatique. Les paragraphes valides sont conservés. Après deux relances ciblées échouées, les marqueurs de mise en forme sont restaurés par alignement si ceux des images et notes sont intacts ; sinon, le repli existant prend le relais. Relances, tokens et restaurations sont journalisés.
-
Les personnages de tomes différents qui ne partagent qu’un titre ou un alias restent distincts. Leur rapprochement est proposé sans fusion d’alias ; un lien automatique exige un nom canonique concordant et des genres compatibles.
-
L’import TXT conserve les paragraphes chinois et japonais séparés par un seul retour à la ligne lorsqu’ils se terminent par une ponctuation CJK, et recolle le texte CJK coupé à largeur fixe sans insérer d’espaces ASCII.
-
La propagation d’un terme laisse intacts les passages volontairement conservés dans la langue source. Son aperçu et son rapport les excluent ; leur alerte reste ouverte et la couverture incomplète.
-
Un nom propre verrouillé qui est aussi un mot courant (« Will », « Dawn ») ne déclenche plus qu’un avertissement lorsqu’il apparaît uniquement en tête de phrase, où la majuscule est ambiguë. Le prompt omet alors la consigne impérative du glossaire mais donne toujours la traduction décidée comme simple indication ; le contrôle reste bloquant au milieu d’une phrase. Un terme qui ne peut pas être confondu avec un mot ordinaire (chiffres, ponctuation) garde son application complète même en tête de phrase.
-
Les termes verrouillés du glossaire acceptent désormais l’accord de chaque élément des composés à trait d’union (comme
loups-garousetGrande-Prêtresse) ainsi que les pluriels irréguliersMesdemoiselles,Messieurs,Mesdames,MesseigneursetGentilshommes. -
Les preuves des référents sont désormais réparties par action, avec la citation source et les citations de chaque rôle dans le même bloc. Les actions écartées sont tracées dans l’inspecteur et ne sont pas transmises comme des faits. Sur douze référents, la fenêtre de 32 k conserve les douze ; un plafond facultatif de 1 000 tokens en conserve un et trace onze absences. Les décisions du lecteur restent obligatoires dans leur portée même si les fiches facultatives sont écartées.
-
Une affirmation non établie sur un personnage ne pouvait plus fixer le genre, les pronoms ou le métier, mais survivait en texte libre. Audit A3 (27/09/2026) : le filtre de preuve (
grounded_analysis) vidait déjà un attribut structuré sans citation source, mais la même affirmation restait utilisable viadescription,relationshipsoutranslation_notes, et atteignait donc quand même la mémoire du livre et le prompt du traducteur comme si elle était établie — un genre ou un métier inventé revenait sous la forme « a female physician » ou « Use she/her ». Ces trois champs libres portent désormais le même contrat de citation que le genre, les pronoms et le métier :description_evidence, puis, un par élément,relationships_evidenceettranslation_notes_evidence, chacun vérifié comme une citation exacte du passage avant d’être conservé, et la citation doit aussi être ancrée au personnage qu’elle prétend décrire — elle doit le nommer, ou partager un paragraphe non coupé avec un passage qui le nomme — pour qu’une phrase sans rapport, ailleurs dans le passage, ne puisse pas passer pour une preuve à son sujet. Une phrase qui établit réellement deux personnages à la fois (une même filiation, un même métier) reste probante pour les deux : partager une citation n’est pas, en soi, une raison de la rejeter. Le mode d’analyse parallèle applique le filtre à l’extraction de chaque passage avant qu’elle ne rejoigne la ligne de temps de réconciliation (app.engines.translation.parallel_analysis) : une affirmation non établie ne peut donc plus devenir un « fait connu » pour un passage voisin avant d’être filtrée. Une décision humaine validée n’est pas touchée : elle s’applique par-dessus ce filtre, jamais au travers de lui. Les prompts intégrés passent enfile-v13(chapter_analysis,chapter_extraction,chapter_reconciliationdemandent désormais la même citation par affirmation sur les champs libres). -
L’arbitrage ne relance plus une critique dont la suggestion figure déjà dans son paragraphe. Il écarte les suggestions déjà appliquées malgré les différences d’espacement ou de guillemets, et accepte un paragraphe inchangé quand la suggestion retenue y est déjà présente.
-
L’autopilote contrôle le texte écrit par l’arbitrage avant le bilan. Chaque réécriture effective déclenche une relecture finale de sa nouvelle révision et un contrôle ciblé de cohérence avec les passages voisins et les relations pertinentes, y compris aux tours suivants. Les passages inchangés gardent leurs verdicts ; les reprises restent bornées et les modifications humaines concurrentes protégées.
-
Les relectures dues par l’autopilote survivent à une réponse invalide du modèle, aux tours suivants et au redémarrage du travail. Chaque relecture finale et contrôle par un juge qualité configuré est suivi pour la révision du passage. Les contrôles manquants sont repris dans la limite des tours et restent explicites dans le bilan après épuisement.
-
Les constats de relecture visant un paragraphe inconnu déclenchent une réparation bornée dans le juge, les relectures séparée, finale et fusionnée, et le contrôle de cohérence. Le constat invalide reste dans la trace de requête ; après épuisement, le contrôle est signalé sans résultat valide au lieu d’accepter un avis vide.
-
Un terme dans une écriture étrangère cité puis expliqué n’est plus traité comme un fragment resté non traduit.
foreign_script(le contrôle unique que les vérifications qualité, l’arbitrage et la relecture finale partagent tous) lit désormais des indices structurels avant de signaleruntranslated: la citation ne contient qu’un seul mot ou un nom court — sans espace ni ponctuation de phrase qui trahirait une proposition, et court là où l’écriture n’a pas d’espace pour borner un mot — la même unité est citée dans la source, et un commentaire l’entoure dans la cible. Une traduction qui gardait 雨宿り, дождь ou νερό pour expliquer le mot échouait ses vérifications, voyait cet échec réémis à chaque tour d’arbitrage, et la relecture finale refusait le bon candidat pour l’avoir corrigé. Un oubli réel reste signalé, entre guillemets ou non — y compris une réplique de dialogue restée non traduite derrière une longue narration bien traduite (une première version de la règle l’excusait dès que le commentaire autour était assez long ; c’est désormais la longueur de l’unité citée elle-même, pas celle de ce qui l’entoure, qui tranche). -
La mémoire de traduction respecte désormais l’ordre des passages et les consignes. Elle ne reprend que les passages antérieurs du même livre ou des volumes antérieurs d’une série, avec des consignes locales identiques (et des consignes du livre identiques entre livres). Les passages courts sont traduits dans leur contexte actuel. Les corrections humaines suivent les mêmes limites.
-
L’audit de cohérence de série s’exécute désormais avant le bilan final de l’autopilote, et résout seul ce qu’il peut. Un terme ou le genre d’un personnage que les modèles ont laissé diverger entre les tomes d’une série — jamais une variation volontaire, un terme verrouillé, ou un genre déjà validé par une personne — converge automatiquement, dans une limite fixée, vers celui de ces choix qui porte déjà une décision humaine, ou sinon (pour un terme, à défaut de toute décision) vers ce que le tome le plus ancien avait établi. Une décision n’est jamais propagée à un tome antérieur à celui où elle a été prise, si bien qu’une révélation plus tardive (un nom tenu secret, un genre dévoilé plus loin dans la série) n’est jamais écrasée en arrière ; un changement de genre non décidé apparu dans un tome plus tardif reste, pour la même raison, non résolu automatiquement. Les fiches de style ne sont pas concernées et restent manuelles. Seul un conflit réel entre deux telles décisions reste signalé, et son nombre alimente désormais le bilan du travail, pour qu’un résultat avec restes le reflète au lieu d’un bilan calculé avant la correction.
-
Supprimer un livre ne retire plus ses tokens des statistiques. Les agrégats d’utilisation quotidiens étaient supprimés avec leur livre, et les requêtes pas encore agrégées partaient avec lui : Statistiques et les compteurs Prometheus perdaient tout ce que le livre avait consommé. Les agrégats d’un livre supprimé restent désormais, et ses dernières requêtes y sont comptées avant son départ. Restaurer l’archive d’un livre supprimé (archives exportées à partir de cette version) reprend sa place dans les statistiques au lieu de le compter deux fois.
-
Les choix éditoriaux EPUB restent cohérents entre l’aperçu, l’export et la livraison. Les titres de chapitre suivent l’ancre du sommaire ou le premier titre de tout niveau ; les titres enrichis inchangés gardent leur mise en forme et les titres modifiés à la main gardent leurs ancres. La couverture est conservée comme fichier du projet, incluse dans son archive et servie par une route dédiée. Sa signature doit correspondre au type déclaré dans le manifeste de l’EPUB source.
-
Supprimer plusieurs volumes d’une série en même temps n’échoue plus. La suppression groupée de la bibliothèque envoie une requête par volume, en parallèle. Chaque suppression était validée, puis recalculait la mémoire de la série dans une seconde transaction : la cascade d’une suppression (premier volume des termes et des identités de série, liens de série) croisait le recalcul d’une autre, et PostgreSQL en arrêtait une — interblocage, ou recalcul qui réécrivait un volume tout juste supprimé. Le volume disparaissait, la requête répondait 500 et la mémoire de série restait en l’état. Un volume de série est désormais supprimé sous le verrou de la série, suppression et recalcul dans une seule transaction : les suppressions d’une série se mettent en file et chacune répond.
[0.22.0] - 2026-09-26
Notes de mise à jour
- Aucune migration, aucun changement du protocole de licence : fonctionne avec le serveur de licences déjà déployé (0.12.0).
- Les prompts intégrés passent en
file-v11(viafile-v10, jamais publiée) : les prompts qui traduisent, relisent, révisent, arbitrent, polissent, jugent ou analysent un passage nomment les deux nouvelles sections de série (voir Ajouté), ettranslationetbook_analysisdisent que la mémoire s’arrête au passage (voir Corrigé). Une version de l’un d’eux enregistrée par un administrateur dans Paramètres › Prompts garde son propre texte : comparez-la au prompt intégré. - À partir de son deuxième volume, les prompts d’un volume de série portent la mémoire de la série : au plus 2 400
tokens selon l’estimation prudente de Libris (un par octet, environ le quart en tokens réels) pour
SERIES_MEMORYet 600 par personnage du passage qu’un volume précédent connaissait, pris dans le budget du contexte facultatif (Budget contexte, 32 000 par défaut depuis cette version, voir plus bas) ; mesuré sur un volume 1 chargé, environ 850 tokens réels de plus par appel. - Les fiches de personnages sont datées par les analyses qu’un livre contient déjà : un livre analysé avant cette version est daté tel quel, rien à relancer. Un fait d’une fiche qu’aucune analyse enregistrée n’énonce (fiche plus ancienne que ses analyses, analyses supprimées avec un chapitre remplacé) compte à partir de la première apparition du personnage, comme avant. Un passage analysé de nouveau par un rattrapage ou une analyse forcée avant cette version a lu tout le livre et peut contenir un lien que l’histoire établit plus tard : la Réanalyse complète le date de nouveau.
- Un prompt de traduction ne contient plus le résumé de la Book Bible (jusqu’à 350 mots) ; il contient à la place les résumés des trois chapitres qui précèdent celui du passage (600 caractères chacun au plus) et de son propre chapitre jusqu’à lui (900 au plus). Sur le livre synthétique de l’audit, les prompts de traduction sont 12 % plus courts en moyenne.
- Des prompts plus riches sur les grandes fenêtres. Le contexte facultatif de chaque appel (fiches, glossaire,
Book Bible, état du chapitre, voisins, mémoire) prend désormais les trois quarts de ce que la fenêtre du provider
laisse une fois les parties obligatoires placées, jusqu’à Paramètres › Mémoire · OpenViking › Budget contexte
(
context_budget), dont le défaut passe de 12 000 à 32 000 tokens estimés. Un 12 000 enregistré — l’ancien défaut, que le formulaire enregistrait avec toute configuration OpenViking — se lit 32 000 ; toute autre valeur est gardée. Mesuré sur un passage réaliste (3 400 caractères, 8 personnages, 30 termes, 10 relations, 4 096 tokens de sortie), une requête de traduction passe d’environ 27 600 à environ 47 700 tokens estimés avec une fenêtre de 64k (environ 6 500 → 11 500 tokens réels, quelque 5 000 de plus par appel ; la Book Bible, en tête du prompt, peut être servie par le cache de prompt du provider), et change à peine avec une fenêtre de 32k (environ 27 600 → 27 800 : son contexte facultatif reste à 12 000). Un volume de série dont le volume précédent a été entièrement analysé (fenêtre de 64k, 16 384 tokens de sortie) passe d’environ 27 800 à environ 36 200 : sa mémoire de série garde désormais les six personnages au lieu de quatre. Pour garder l’ancienne taille, enregistrez un Budget contexte de 11 999 ou moins.
Ajouté
- Un volume de série est traduit avec ce que ses volumes précédents ont établi. La Series Bible, les relations de
série et ce qu’une personne avait décidé au volume 1 n’atteignaient aucun prompt du volume 2 : un volume héritait
des termes, des corrections et des noms de ses volumes précédents, rien d’autre ; le volume 2 ignorait de quoi
parlait le volume 1, où en étaient deux personnages à sa fin, le genre décidé par un lecteur et le tu ou le vous de
sa fiche de style. Chaque prompt d’un volume de série (traduction, relectures, révision, relecture finale,
arbitrage, polissage, juge qualité, analyse) porte désormais deux sections construites à partir de ses volumes
précédents seulement (même série, même propriétaire, même paire de langues, plus tôt dans l’ordre de lecture),
jamais d’un volume suivant.
SERIES_MEMORY, la même pour tout le volume : la Series Bible validée par une personne, sinon les conventions des bibles des volumes précédents, et le « précédemment dans la série », le résumé des volumes précédents, du plus récent au plus ancien, avec la fin du dernier.SERIES_CHARACTERS, une par personnage du passage qu’un volume précédent connaissait, tel que le dernier l’a laissé : noms, rôle, genre et pronoms (decided_by_readerquand une personne les a décidés), registre et manière de parler, dernière relation avec chaque autre personnage du passage et formes d’adresse décidées par la fiche de style d’un volume. Une Series Bible validée atteint un volume sans ce qu’elle date de ce volume ou après (entrées de chronologie, personnages par leur premier volume) ni ce qu’un volume suivant a écrit mot pour mot ; son contenu non daté (univers, conventions, une note) est la règle de la personne pour la série et il est envoyé.SERIES_MEMORYvient juste après les passages voisins, avant toute autre mémoire, et ne prend jamais sur leur part ; un personnage passe après les fiches du livre, et les règles, fiches et décisions du livre l’emportent là où elles diffèrent. Le contexte réduit d’un passage trop long pour sa fenêtre garde le genre, les pronoms et le registre que les volumes précédents ont décidés pour les personnages qu’il nomme.
Corrigé
- L’audit de cohérence de série ne compare que des volumes d’une même paire de langues. Une série traduite en français et en espagnol voyait chaque terme « traduit de deux façons » et chaque personnage doté de deux genres, et Appliquer à toute la série écrivait la traduction française dans le glossaire des volumes espagnols. L’audit compare désormais les volumes de chaque paire de langues (sous-tags primaires) entre eux, ne contrôle les termes verrouillés de la série que dans les volumes de la paire de la série, et une réponse s’applique aux volumes des paires où la question était posée.
- Les relations de série suivent leurs volumes. Une relation entre deux personnages de la série était écrite une fois, avec la formulation du premier volume qui l’énonçait, puis jamais mise à jour ni supprimée : supprimer ou détacher un volume laissait ses relations dans la série (onglet Relations, Series Bible), et un volume qui énonçait de nouveau une relation, autrement, n’y changeait rien. Chaque recalcul de la série les reprend désormais des volumes : une relation commence là où l’ordre de lecture l’énonce d’abord, se lit comme sa dernière formulation, et disparaît quand plus aucun volume ne l’énonce.
- Un volume ne reçoit plus le nom qu’un volume postérieur donne à un personnage. L’identité de série d’un personnage prenait le nom du premier volume analysé : le volume 3 analysé avant le volume 1 faisait de « Lelouch vi Britannia », le nom que révèle le volume 3, le nom que le volume 2 devait garder pour l’homme masqué Zero, et l’identité commençait au volume 3. Un volume reçoit désormais chaque personnage sous les noms qu’employaient ses volumes antérieurs, celui du plus récent d’abord ; une identité commence au premier volume de l’ordre de lecture qui lui est relié et, sauf si une personne l’a validée, prend le nom et la fiche de ce volume (le nom postérieur reste un alias) : la mémoire de série est la même quel que soit l’ordre d’analyse des volumes. Lieux, organisations et objets sont datés de même.
- Le prompt d’un passage ne connaît plus ce que l’histoire révèle après lui (audit du 2026-09-26, H2). Les fiches de personnages étaient celles du livre entier : une fiche prend son nom le plus long et rassemble les noms, le genre et les relations de tous les chapitres, si bien que « Graymask = Mira Voss », révélé au passage 13 du livre de l’audit, figurait dans le prompt des 13 passages qui le précèdent ; les relations écrites en texte libre sur une fiche (« frère de Nunnally ») échappaient à la datation du graphe de relations. Chaque nom et chaque fait d’une fiche est désormais daté par les analyses enregistrées passage par passage, et un prompt ne reçoit que ce que l’histoire a établi jusque-là : un personnage masqué garde sa propre fiche sous son propre nom jusqu’à ce que l’histoire le démasque, une relation écrite sur une fiche apparaît à partir du passage qui l’énonce, et les extrémités des relations, le contexte réduit et le registre de personnages de l’analyse suivent la même règle (une analyse lit ce que les passages strictement antérieurs ont établi). Un genre que l’histoire n’établit que plus loin est omis, et la fiche demande au modèle, sans le dire, de garder l’ambiguïté de la source. Ce qu’une personne a décidé — un genre ou des pronoms, les noms d’une identité confirmée, une fiche validée — s’applique à chaque passage ; quand cela devance l’histoire, la fiche le signale et le modèle a pour consigne de ne pas le dévoiler. Les onglets Book Bible et Personnages montrent toujours tout.
- La Book Bible ne raconte plus la fin à chaque passage ; l’histoire jusqu’ici, si. Son résumé, écrit à partir du livre entier, accompagnait chaque prompt dès le premier passage, et le résumé de chapitre n’atteignait jamais une traduction (il n’était envoyé qu’une fois son chapitre terminé, ce qu’il n’est jamais pour un passage de ce chapitre). Un passage reçoit désormais les champs de la Bible qui ne racontent pas l’histoire (genre, ton, narration, temps, public, consignes, jeux de mots, honorifiques, conventions : toujours le préfixe mis en cache du prompt), les résumés des chapitres qui précèdent le sien et celui de son chapitre jusqu’au passage d’avant. Une Bible validée par une personne est envoyée de la même façon : ce qu’elle décide garde son autorité, son résumé reste dans l’onglet. Le prompt de la Book Bible tient désormais l’intrigue, les identités cachées et les rebondissements hors de tous les champs sauf le résumé.
- Une analyse de rattrapage ne lit plus la suite du livre et ne fait plus reculer son chapitre. Un passage perdu au premier tour est redemandé une fois tous les autres enregistrés (#161) : il lisait les fiches du livre entier et le résumé de la fin de son chapitre, et les enregistrait à son propre passage (sur le livre de l’audit, un spoiler enregistré et 8 prompts) ; il remplaçait ensuite le résumé du chapitre par le sien, arrêté à lui-même. Il ne lit plus que ce qui le précède, et un résumé de chapitre ne fait plus qu’avancer ; ce qu’une personne a ajouté à un chapitre reste.
- Une analyse forcée repart de zéro (audit M9). La Réanalyse complète supprimait les analyses des passages mais gardait les fiches et la Book Bible : la nouvelle analyse du passage 1 lisait les anciennes fiches et y réécrivait leurs liens (80 prompts d’analyse du livre de l’audit), et une Bible validée par le pilote automatique n’était jamais reconstruite. Ce qu’une fiche tient de l’ancienne analyse reste désormais hors des prompts tant que la nouvelle ne l’a pas établi à nouveau, une Bible validée par le pilote automatique est rouverte et reconstruite, et une Bible validée par une personne reste la sienne.
- Le banc d’essai de l’analyse (
tests/analysis_world.py) ne lisait que la dernière des sections qu’un prompt répète : il voyait un prompt fautif là où il y en avait 13. - Un passage reçoit la mémoire des noms qu’il décline. Le glossaire, les fiches de personnages, leurs relations et
les termes de série d’un passage étaient choisis sur le nom exact : un passage russe qui dit Наташу pour Наташа, un
passage allemand qui dit Peters pour Peter ou un passage anglais qui dit Demon Lords n’en recevait aucun, et avec
une source polonaise, tchèque, finnoise, turque ou hongroise la plupart des noms sont déclinés. Le contexte cherche
désormais un nom tel que la langue source le fléchit : le nom entier et les terminaisons courtes de ses cas (russe,
ukrainien, biélorusse, bulgare, serbe, polonais, tchèque, slovaque, slovène, croate, lituanien, letton, grec), de
ses suffixes (finnois avec son alternance consonantique, estonien, hongrois, turc après l’apostrophe d’un nom et
avec ses consonnes adoucies), les cas et adjectifs allemands, les pluriels et possessifs anglais, les terminaisons
néerlandaises et scandinaves, les pluriels des langues romanes, les préfixes de l’arabe et de l’hébreu ; jamais un
début tronqué (Мечник n’est pas Мечта, Jana n’est pas Jan). À l’inverse, un nom à majuscule garde sa casse, comme le
contrôle en sortie le faisait déjà : « Will » n’amène plus la fiche de Will dans « I will go ». Les écritures sans
espaces ne changent pas. La même règle choisit les personnages qu’un volume antérieur de la série connaissait
(
SERIES_CHARACTERS), le contexte réduit et les personnages du contrôle de cohérence. - Un passage raconté en pronoms reçoit les fiches de sa scène. « She laughed softly. » ne nommait personne :
aucune fiche de personnage n’atteignait le prompt, alors que c’est là qu’un genre décide la traduction — et une
phrase japonaise, chinoise ou coréenne omet souvent son sujet. Le contexte ajoute désormais les fiches des
personnages de la scène : ceux que liste l’analyse du passage, ceux dont les événements des passages juste avant
disent qu’ils savent quelque chose, puis ceux nommés en dernier dans les douze passages précédents du chapitre, du
plus récent au plus ancien ; quatre au plus, seulement des noms qui désignent un seul personnage, avec leurs
relations entre personnages de la scène seulement ; chaque fiche ne dit, comme les autres, que ce que le récit a
établi à ce moment. Elles cèdent la place les premières quand la fenêtre manque, et l’inspecteur de contexte montre
pourquoi chacune a été choisie (
why). Jusqu’à quatre fiches de plus pour un tel passage (quelques centaines de tokens chacune), dans le même budget. - La mémoire interne trouve les souvenirs d’un passage japonais, chinois ou coréen. Un souvenir était noté sur
les mots de trois lettres ou plus qu’il partageait avec le passage ; dans une écriture sans espaces, un « mot » était
une proposition entière : un souvenir qui nommait le même personnage que le passage obtenait 0 et n’était jamais
proposé (un nom de deux caractères n’était même pas un mot). En anglais, l’inverse : un souvenir hors sujet obtenait
0,5 grâce à « the », « was » et « that », et les noms de champs d’un souvenir (
summary,event) correspondaient à tout passage employant ces mots. Les souvenirs sont désormais notés sur les mots porteurs de sens (les mots-outils fréquents de l’anglais, du français, de l’allemand, de l’espagnol, de l’italien, du portugais, du néerlandais, du russe, de l’ukrainien, du polonais et du tchèque ne comptent plus), sur les paires de caractères voisins dans les écritures sans espaces (sauf les paires de particules ou de caractères grammaticaux), et sur leur seul texte. Vaut pour le backendinternalet la partie base de données dehybrid. - Le contexte utilise la fenêtre qu’il a, et cède la place dans un ordre sensé. Le contexte facultatif était
plafonné à 12 000 tokens estimés quelle que soit la fenêtre — environ trois mille tokens réels de mémoire pour un
modèle de 64k — par un réglage rangé avec ceux d’OpenViking alors qu’il vaut pour tous les backends, et sacrifié à
la seule autorité : une Book Bible non validée partait avant toute fiche, relation ou état du chapitre (la relecture
finale et l’arbitrage la perdaient en premier), les termes non verrouillés du livre étaient coupés sans un mot (96
gardés sur 400), et les termes de série non verrouillés, tous obligatoires, débordaient la fenêtre (400 décisions de
série non verrouillées rendaient le passage intraduisible). Le contexte facultatif prend désormais les trois quarts
de la place que la fenêtre laisse, jusqu’au Budget contexte (voir les notes de mise à jour), et se remplit dans
cet ordre : décisions humaines validées de la mémoire, passage le plus proche de chaque côté, décisions de série non
verrouillées d’une personne, Book Bible (validée ou non) et histoire jusqu’ici, fiches des personnages nommés,
termes non verrouillés du livre et de la série, état du chapitre, fiches des personnages de la scène, relations,
voisins plus lointains, et enfin la mémoire retrouvée ; un type servi tôt qui prendrait plus que sa part (un quart,
la moitié pour la Bible) attend un rang plus lointain. Les termes de série non verrouillés deviennent facultatifs et
bornés (ceux gardés restent dans
SERIES_CONVENTIONS) ; les verrouillés restent obligatoires. Tout ce qui est écarté — les voisins lointains passage par passage, chaque terme de série non verrouillé — figure dans l’inspecteur de contexte avec sa raison, et la nouvelle entréebudgeten fait le compte. Le décompte en octets qui protège la fenêtre ne change pas. - Un terme verrouillé arrive au modèle avec sa description. Le glossaire verrouillé ne donnait au modèle que la source et la traduction : la description écrite par une personne (« un titre, jamais un nom », « le mot des elfes pour la source ») accompagnait les termes non verrouillés mais jamais les verrouillés, si bien qu’une traduction imposée s’appliquait à l’aveugle. Chaque terme verrouillé porte désormais les 160 premiers caractères de sa description, s’il en a une (au plus quelque 170 tokens estimés, 40 réels, par terme verrouillé que disent le passage ou ses voisins ; le contexte réduit garde ses termes sans description).
- Une clé OpenViking devenue illisible ne vide plus la mémoire. Quand la
SECRET_KEYchangeait, la clé OpenViking enregistrée devenait illisible : la recherche était coupée, et un volume au backendopenvikingne gardait que les décisions validées de la base — aucune mémoire, avec une erreur vide dans l’inspecteur de contexte. La mémoire de la base de données prend désormais le relais, entière, comme quand OpenViking tombe en panne, et l’erreur de récupération de l’inspecteur dit que la clé est illisible et doit être enregistrée de nouveau. Une recherche désactivée dans les paramètres se replie de la même façon (openviking_search: disabled).
[0.21.0] - 2026-09-26
Notes de mise à jour
- Aucune migration, aucun changement du protocole de licence : compatible avec le serveur de licences déployé (0.12.0). Les livres déjà importés restent tels quels : les lignes de leur site source restent dans leurs passages.
- Nouveaux réglages facultatifs :
AUTOPILOT_STYLE_MIN_CONFIDENCE(0,8) etQUALITY_JUDGE_PROVIDER(vide : pas de juge qualité), tous deux aussi dans Paramètres › Pilote automatique, etQUALITY_REWORK_SHARE(0,25). Un livre peut choisir son propre juge, ou aucun, dans ses réglages. - L’analyse de chaque volume se termine désormais par un appel au modèle de plus,
style_proposal, quand sa fiche de style laisse un champ ouvert (quelques milliers de tokens, une fois par volume). Avec un juge qualité, chaque passage coûte un appel de plus sur le provider du juge, et une correction et une seconde lecture pour les passages où il trouve des erreurs. - Les prompts intégrés passent de
file-v5+rules-v3àfile-v9+rules-v6: deux nouveaux prompts,style_proposaletquality_judge;consistency_check,review_revision,autopilot_arbitration,polishing,final_reviewettranslation_revisionchangent (voir Corrigé), et les listes de fautes couvrent plus de langues (voir Ajouté). Une version de l’un d’eux enregistrée par un administrateur dans Paramètres › Prompts garde son propre texte : comparez-la au prompt intégré.
Ajouté
- Les fautes de nouvelles paires de langues sont nommées dans les prompts. Jusqu’ici, seule une traduction vers le français recevait la liste des fautes qu’un modèle fait sans les voir (#180) ; toutes les autres paires n’avaient rien. L’anglais a désormais sa liste, quelle que soit la source (articles et nombre depuis une langue qui n’en a pas, un seul temps de narration, pronoms que la source omet, dialogues qui sonnent parlés), tout comme l’espagnol, l’allemand, l’italien, le portugais, le japonais, le chinois et le coréen (la grammaire et les tournures traduites de chacun). Les paires des webnovels japonais, chinois et coréen → anglais ont les leurs (suffixes honorifiques et termes d’adresse, particules et onomatopées, mots en katakana, expressions figées, vocabulaire de cultivation, niveaux de langue), et anglais → espagnol, allemand, italien, portugais, japonais, chinois et coréen leurs faux amis, calques et expressions. Comme pour le français, le traducteur les évite, le polissage les corrige, la relecture cherche chacune et l’arbitrage pèse les corrections à leur aune ; la fiche de style et les règles de l’utilisateur passent avant. Elles ajoutent 100 à 350 jetons à chaque appel de ces paires, servis par le cache de prompt du fournisseur.
- Les lignes qu’un site source écrit dans chaque chapitre sont proposées à l’exclusion dès l’import (#182). Un site
qui publie des chapitres à copier ajoute ses propres lignes à leur début ou à leur fin (« Visit and read more novel
to help us update chapter quickly. », « Use arrow keys (or A / D) to PREV/NEXT chapter ») : importées avec le texte,
elles étaient comptées, traduites, relues et arbitrées chapitre après chapitre (24 des 178 décisions d’arbitrage d’un
webnovel portaient sur leur traduction). Pour des chapitres TXT, Markdown, HTML et DOCX, y compris ceux d’un fichier
découpé, l’assistant d’import liste désormais les lignes trouvées parmi les cinq premiers et les cinq derniers
paragraphes d’au moins trois chapitres et de 30 % d’entre eux (la même ligne aux espaces et à la casse près), avec
Exclure ces lignes coché. Ce qui reste coché n’est pas importé, donc ni compté dans le quota de la licence, ni
traduit ; l’estimation d’import compte sans. Le choix est enregistré sur le livre (
import_meta.excluded_lines) et appliqué à chaque chapitre ajouté ensuite — par l’assistant, par l’API d’automatisation ou par une source suivie, qui n’ont pas d’aperçu et n’appliquent que ce que le livre a enregistré —, seulement au début et à la fin d’un chapitre : les mêmes mots au milieu de l’histoire sont gardés, et un chapitre fait seulement de ces lignes est gardé en entier. Les fichiers source conservés et les archives de projet gardent les lignes ; une traduction ne les montre jamais. - Un mot qui mêle les lettres de plusieurs écritures est signalé (
mixed_script, un avertissement sur la traduction, avec le mot et leur nombre). Les sites glissent leur nom dans les chapitres sous une forme déguisée qui change d’un chapitre à l’autre (freeweɓnovel.cѳm,ƒгeewebnovёl.com,fɾeewebnoveℓ.co๓) : 39 passages du même livre l’avaient recopié dans leur traduction sans que rien ne le signale. Un mot est signalé quand il mêle des alphabets confondables (latin, cyrillique, grec, arménien…), ou quand un mot latin porte une lettre de l’alphabet phonétique, un symbole de lettre ou un chiffre d’une autre écriture ; le latin accentué (français, polonais, tchèque, roumain, vietnamien) et le japonais qui mêle kanji, kana et latin ne le sont jamais. - La fiche de style est proposée à partir du livre (#183). Une fiche vide laissait le registre, le temps ou les gros
mots au modèle, passage par passage, et la traduction d’un narrateur à la première personne, au présent, familier et
cru dérivait de « J’abhorre » à « partenaires de dating ». À la fin de l’analyse, un appel léger lit le début du livre,
quelques passages plus loin et la Book Bible, et propose une valeur pour chaque champ encore ouvert, avec une confiance
et une citation de la source ; les honorifiques seulement si la source en emploie, une valeur que la fiche ne connaît
pas est écartée. Sous pilote automatique, une proposition qui atteint
AUTOPILOT_STYLE_MIN_CONFIDENCEest écrite dans la fiche du volume et chaque proposition est journalisée (analysis/style_sheet) ; sinon, les propositions attendent dans l’écran de la fiche de style, chacune avec Appliquer la proposition, et Proposer à partir du livre redemande à tout moment (POST /api/projects/{id}/style/propose,402sans licence). Un champ décidé par une personne ou par la série n’est jamais écrasé, et une proposition qui échoue ne retient jamais la traduction. Le prompt,style_proposal, se modifie dans Paramètres › Prompts comme les autres. - Un juge qualité relit chaque passage traduit et fait corriger ses erreurs (docs/quality.fr.md). Un modèle
d’un autre provider — Codex par un compte ChatGPT, ou toute API compatible OpenAI ou Anthropic — relit chaque
passage juste avant de le clore, avec son contexte et les fautes de sa paire de langues, comme le dernier
correcteur avant publication (opération
quality_judge). Ses erreurs (changement de sens, pronom ou complément perdu, omission, faute de grammaire ou d’orthographe, calque ou faux ami qu’un lecteur natif remarque…) sont corrigées sur le modèle du juge, sous les gardes du polissage, et la correction n’est gardée que si le juge y trouve ensuite moins d’erreurs, dans la limite deQUALITY_REWORK_SHARE(25 %) des passages d’un travail ; les erreurs qu’il trouve encore rejoignent les points de relecture du passage (ses avertissements ne servent qu’à sa correction). Le juge lit la consigne du travail comme toute relecture et n’est jamais remplacé par le modèle supérieur. Il se choisit dans Paramètres › Pilote automatique (QUALITY_JUDGE_PROVIDER) parmi les providers de l’installation — le provider d’un membre ne lit jamais les livres des autres — et un livre peut en nommer un autre que son propriétaire peut utiliser, ou aucun ; le choix est revérifié à chaque passage. Sans juge, rien ne change, et un juge qui ne répond pas ne fait jamais échouer un passage. Rien ne tourne en local : un petit VPS suffit. Une métrique de traduction, MetricX-24, a d’abord été mesurée puis écartée : sur vingt paragraphes corrigés d’un light novel anglais → français, elle repérait les fautes grossières mais pas les calques (8 sur 20), et elle demandait PyTorch et plusieurs gigaoctets de mémoire.python -m app.benchfait comparer des systèmes par le juge sur un fichier ou deux volumes (erreurs, avertissements, et chrF contre des références) avant une publication.
Corrigé
-
Un audit des changements de cette version a resserré ce qui avait été fusionné vite :
- l’assistant d’import liste chaque ligne du site source avec sa propre case, pour qu’une ligne récurrente de
l’histoire (un message système, une réplique fétiche) puisse être gardée ; l’estimation compte les lignes
décochées (
keep_line) ; - la copie d’un livre dans une autre langue n’emporte plus les valeurs de fiche de style que le pilote automatique avait décidées pour la première langue (guillemets français pour un livre anglais) : elles sont proposées à nouveau ; redemander des propositions garde la trace de ce que le pilote a appliqué ;
- une proposition de style dont la citation est introuvable dans le livre reste sous le seuil du pilote automatique, et une narration au passé composé n’est proposée que pour le français et l’italien ;
- l’export bilingue compte comme manquant un passage resté en langue source, comme l’export texte ; l’export Word retire les guillemets qu’un modèle a ajoutés à une pensée non citée, comme les autres sorties ; les guillemets en coin, pleine chasse et CJK (「」 〝〟 " 〈〉 《》 ❝❞) comptent désormais comme une citation de la source ;
- un terme dont la description du modèle dépassait la limite du glossaire peut de nouveau être modifié (MCP
edit_term) ; - les listes de fautes n’interdisent plus ce qui est correct : un plus-que-parfait dont le locuteur a besoin, avoir avec un verbe de mouvement suivi d’un complément (« il avait sorti son épée »), le possessif sur une partie du corps sujet (« ses yeux brillaient »), une narration au présent dans une traduction anglaise ; plusieurs faux amis sont nommés avec leur sens.
- l’assistant d’import liste chaque ligne du site source avec sa propre case, pour qu’une ligne récurrente de
l’histoire (un message système, une réplique fétiche) puisse être gardée ; l’estimation compte les lignes
décochées (
-
Une remarque de cohérence n’est close qu’en corrigeant le paragraphe qu’elle vise. Le contrôle de cohérence du livre enregistrait ses remarques sans le paragraphe qu’elles nommaient : l’arbitrage lisait chacune comme une remarque sur tout le passage, « acceptait » une remarque sur le tutoiement d’Alice sans changer un mot, ou réécrivait un autre paragraphe, et la closait dans les deux cas. Une remarque nomme désormais son paragraphe en premier, comme les contrôles automatiques : retenue, elle doit corriger ce paragraphe et lui seul, sinon la réponse est refusée et la remarque reste ouverte pour le tour suivant. Les remarques enregistrées avant cette version restent lues comme portant sur tout le passage.
-
Le contrôle de cohérence juge les formes d’adresse avec les règles et les relations qui les décident . Ses échantillons ne portaient que les consignes du livre et la fiche brute de leur sujet : ni fiche de style (donc pas les paires qui disent qui tutoie qui), ni relation entre les personnages, ni la consigne du travail, et une fiche dont les champs décidés s’appelaient
decidedalors que le prompt cherchedecided_by_reader: un genre décidé par une personne se lisait comme une supposition de plus. Chaque échantillon porte désormais aussi les règles de l’utilisateur (celles du livre, la consigne du travail, les règles de la fiche de style, celles d’un passage et de son chapitre), les relations entre les personnages de ses passages établies avant le dernier d’entre eux, avec leur position (les validées et les plus récentes d’abord, 12 au plus), et les fiches des autres personnages présents dont une personne a décidé le genre ou les pronoms (8 au plus) ; la fiche du sujet nomme ces champsdecided_by_reader. Quelques centaines de tokens par échantillon. -
Le contexte réduit garde la mémoire de ce que le passage nomme. Le contexte sur lequel un passage se replie quand son contexte complet ne tient pas dans la fenêtre (l’arbitrage) ou échoue sans cesse (échelon 4 de l’échelle de récupération) ne portait que le glossaire verrouillé et la fiche de style : ni les identités confirmées et conventions de série qu’un contexte complet déclare obligatoires, ni fiche de personnage (un genre décidé par un lecteur pouvait y être défait), ni terme non verrouillé, ni la consigne du travail. Il porte désormais aussi la consigne du travail, les identités confirmées et les conventions de série de ce que le passage nomme lui-même, une fiche minimale de chaque personnage qu’il mentionne (alias, genre, pronoms, registre, ce qu’un lecteur a décidé) et le glossaire non verrouillé. Il reste réduit : ni voisins, ni contexte du livre, ni relations, ni mémoire récupérée, 8 fiches et 30 termes de chaque sorte au plus, et sur une fenêtre étroite la mémoire cède avant les règles. Sur le passage de l’audit, son message passe de 800 à 1 480 tokens, la moitié de celui d’un contexte complet.
-
La consigne d’un travail suit ses passages dans toutes les étapes qui les jugent ou les réécrivent. La consigne donnée à un travail (« Alice vouvoie le roi » : Retraduire › Avec une instruction…, ou
instructionde l’API d’automatisation et des outils MCP) n’atteignait que la traduction, le polissage et les révisions. La relecture, la relecture et révision en un appel, la relecture finale, l’arbitrage et la réparation par groupes de paragraphes jugeaient ou réécrivaient le passage sans elle, et la relecture fusionnée pouvait défaire ce qu’elle demandait. Elle accompagne désormais le passage dans toutes ces étapes (USER_RULES.this_request) ; le contrôle de cohérence et le contexte réduit la reçoivent aussi. -
Les prompts nomment ce qu’on leur envoie et ce qu’un lecteur a décidé. La relecture et révision en un appel et l’arbitrage, les deux étapes qui réécrivent après avoir jugé, ne disaient rien de
decided_by_reader, que la traduction, le polissage, les révisions et les autres relectures connaissent : un genre décidé par un lecteur pouvait y être « corrigé » en sens inverse. Le polissage recevait les règles de l’utilisateur, le glossaire verrouillé et les conventions de série sans un mot à leur sujet ; la relecture finale sesTECHNICAL_CHECKSetPREVIOUS_CRITIQUES, et sa révision sesTECHNICAL_CHECKS, jamais nommés. Chaque prompt dit désormais ce que sont ces sections et ce qu’elles imposent ; l’arbitrage apprend aussi queUSER_RULESpassent avant toute autre donnée et qu’une proposition qui nomme un paragraphe se règle dans ce paragraphe. -
L’analyse d’un volume n’échoue plus sur des personnages fusionnés en chaîne. Quand l’analyse rattachait un personnage à un deuxième, puis ce deuxième à un troisième, un nom du premier pointait encore vers la fiche disparue : la consolidation s’arrêtait avec un simple nombre pour erreur (« 4 », « 50 ») et tous les volumes suivants de la série l’attendaient. Chaque nom suit désormais la fusion. Relancez l’analyse des volumes qui ont échoué ainsi.
-
Une traduction française ne garde plus la ponctuation de l’anglais dont elle vient. Sur un chapitre de light novel traduit, la machine écrivait « Je le ressens vraiment, » s’exclama-t-il (la virgule dans le guillemet, comme en anglais), collait ses tirets aux mots d’une incise (désormais—bien que—et) sur une page qui espaçait les autres, mêlait « ?! » et « ? ! » dans une même scène et mettait une espace avant les points de suspension d’un mot laissé en suspens (« Ce petit chanceux … ! »). Ce que la machine écrit en français est désormais composé comme le ferait un typographe : la virgule sort du guillemet fermant avant une incise, un tiret collé à un mot est espacé (pas entre deux nombres ni après une apostrophe), un groupe de ! et de ? s’écrit sans espace (« ?! ») et les points de suspension se collent à leur mot. Comme le reste de la typographie, cela ne touche que le texte de la machine, à l’enregistrement et à la sortie d’un livre écrit avant ; le texte d’une personne reste tel qu’elle l’a tapé.
-
Une pensée que la source ne cite pas ne devient plus une réplique. La pensée d’un personnage, en italique et sans guillemets dans le livre, revenait du modèle entre guillemets (« Je suis… je suis une horrible personne… ») et le lecteur l’entendait dite à voix haute. Quand un passage de la source ne contient aucun guillemet, dans aucune écriture, ni tiret de dialogue, la seule paire de guillemets que la machine a mise autour de tout le passage traduit est retirée, quelle que soit la langue cible, à l’enregistrement et dans chaque sortie d’un livre écrit avant. Deux citations, une citation à l’intérieur du passage et le texte d’une personne ne sont jamais touchés.
-
Les prompts anglais → français nomment les fautes d’un second chapitre de light novel. Traduit, relu et poli, le chapitre gardait « J’ai abandonné » pour I abandoned her (l’objet disparu : j’ai renoncé), « un appel à l’aide de son frère » pour a cry for her brother’s help, « Ils avaient sûrement juste sorti », « troubrait », « écoutait cette confession […] se déversait », « celui en qui elle s’était éprise », « quand ils se sont retrouvés » dans un récit au passé simple, un plus-que-parfait dans une réplique, « J’ai l’air d’être en retard » pour Looks like I’m too late, « s’excuser » pour excuse herself, « gouvernante » pour attendant, « à l’époque » pour le soir même, « Toux ! » pour Cough!. La fiche du français nomme désormais les temps d’un récit au passé simple et des répliques qu’il contient, la grammaire que l’œil saute (être avec les verbes de mouvement, infinitif après un verbe de perception, s’éprendre de, mots qui n’existent pas) et l’article devant les parties du corps ; la fiche anglais → français nomme le pronom complément que l’anglais exprime, d’autres faux amis et calques, la virgule de série et les bruits nommés au lieu d’être écrits. Chaque opération qui écrit ou juge un passage anglais → français les reçoit (environ 1 000 jetons, servis par le cache de prompt du fournisseur). Les relectures apprennent aussi que Libris compose désormais lui-même les tirets et la virgule voisine d’un guillemet fermant.
-
L’estimation d’import compte un fichier trop long pour un seul chapitre. Un tel fichier, importé découpé à ses titres (la forme habituelle d’un long webnovel), comptait zéro mot, zéro passage et un chapitre : l’estimation disait que le livre tenait dans le quota quelle que soit sa taille. Il est maintenant compté comme les chapitres qu’il deviendra à l’import.
-
Un EPUB dont la feuille de style nomme ses polices ou ses images avec la mauvaise casse s’exporte de nouveau. Une source retouchée avec Sigil peut garder
url("../fonts/ARIALUNI.ttf")dans sa CSS alors que le fichier est dansFonts/: une liseuse sur un système insensible à la casse le trouve, EPUBCheck répondRSC-007et l’export du livre entièrement traduit était refusé (« EPUBCheck signale un EPUB invalide »). À l’export, unurl()d’une feuille de style du manifeste qui ne nomme aucun fichier du livre, mais exactement un fichier à la casse près, pointe désormais sur ce fichier. Le texte et les autres références ne sont pas modifiés, et EPUBCheck reste un contrôle bloquant. -
Une proposition de l’IA acceptée ne transforme plus une erreur du modèle en correction humaine protégée. Quand le modèle devait écrire la correction qu’une personne avait acceptée (une suggestion libre, appliquée en arrière-plan par Accepter ou Tout accepter), son paragraphe était enregistré comme correction humaine sans contrôle du glossaire verrouillé : un paragraphe qui perdait un terme verrouillé du livre, de sa série ou d’un glossaire partagé était écrit, et la revue finale comme l’arbitrage, qui ne touchent jamais un passage humain, laissaient l’erreur en place pour de bon. Le paragraphe réécrit passe désormais le glossaire verrouillé comme une traduction : une réponse qui perd un terme verrouillé est redemandée, et si elle ne le garde jamais, la proposition n’est pas appliquée, avec la raison, et rien n’est écrit. Ce que le modèle a écrit est enregistré comme texte machine (origine
accepted_proposal), que les contrôles et passes suivants examinent encore, et n’est jamais validé ; un passage qu’une personne avait déjà corrigé reste le sien. -
L’outil MCP
edit_termne déverrouille plus un terme qu’on ne lui a pas demandé de déverrouiller. Il envoyait le terme entier à la route qu’utilise l’interface, qui remplace chaque champ : un agent qui ne nommait que la source et la traduction (les deux champs que l’outil exigeait) remettait le reste aux valeurs par défaut, si bien qu’un terme verrouillé décidé par une personne était déverrouillé, perdait sa dérogation à la série, sa catégorie et sa description, et qu’un terme proposé était accepté, le tout en silence. L’outil lit désormais le terme d’abord et ne change que les champs qu’on lui donne, commeconfigure_booketupdate_series; seulsbook_idetterm_idsont obligatoires, un appel qui ne nomme aucun champ est refusé, etacceptedpeut être donné explicitement. La route HTTP garde son remplacement complet. -
Un paragraphe que le modèle rend dans la langue source n’est plus compté comme traduit. Dans un livre anglais → français, un modèle qui rendait un paragraphe anglais mot pour mot faisait lever l’avertissement
unchanged; l’arbitrage l’écartait, l’avertissement était clos et plus jamais relevé, et le livre finissaitcompleted, son exportcomplete, le passage noté 98. L’alerte est désormais relevée après l’arbitrage tant que le paragraphe est le texte source, comme une erreur que le texte porte encore, et un passage dont la traduction est encore le texte source (une alerteunchangedouuntranslatedouverte que son texte actuel mérite encore, sur un passage que personne n’a validé) est un résiduel comme un passage conservé en original : listé dans le rapport du pilote automatique avec la raison du contrôle (le livre finitcompleted_with_residuals), dans lesresidualsdu rapport de livraison, et compté comme manquant dans les exports texte, dont le chapitre n’est pluscomplete. La traduction est toujours écrite — un nom, une citation ou une ligne gardée en original à dessein sont légitimes, et le seuil de cinq mots du contrôle ne change pas — et traduire le passage, résoudre son alerte ou le valider règle la question. -
Hors pilote automatique, un polissage ou une révision que le modèle rate obstinément ne fait plus passer une bonne traduction en erreur. Quand un polissage, une relecture ou une révision répondait encore de façon invalide après ses tentatives et sa réparation — un polissage qui perdait à chaque fois un terme verrouillé, par exemple —, le passage dont la traduction valide était déjà enregistrée passait en
error, ne se terminait jamais, et le travail finissait par demander une récupération après six appels pour rien. Le garde-fou qui refuse le texte fautif est conservé ; l’étape est désormais abandonnée : la traduction déjà enregistrée reste, le passage se termine avec l’avertissement « Étape non appliquée après des réponses invalides du modèle » (codeimprovement_skipped), et le journal des décisions garde la raison, comme le faisait déjà le pilote automatique. Une panne du provider, un refus ou des identifiants manquants pendant ces étapes arrêtent toujours le passage comme avant. -
Deux termes verrouillés qui se chevauchent ne refusent plus la bonne traduction. Avec « Dragon → Wyrm » et « Red Dragon → Dragon Rouge » verrouillés, « le Dragon Rouge » était refusé faute de « Wyrm », alors que « Dragon » n’apparaissait qu’à l’intérieur de « Red Dragon », et le prompt demandait les deux. Un endroit de la source couvert par un terme verrouillé plus long appartient désormais à ce terme : le contrôle n’y exige plus le terme court, et le prompt ne propose le terme court que là où le passage ou ses voisins le disent seul.
-
Un terme verrouillé en allemand, en espagnol, en russe ou dans une autre langue n’est plus satisfait par un mot qui commence seulement comme lui. Hors français et anglais, le contrôle gardait les premières lettres du terme et laissait varier la suite : « Schwein » et « Schwester » valaient « Schwert », « Espalda » et « Espadachín » valaient « Espada ». Le mot entier est désormais exigé, suivi des terminaisons de sa langue : cas, pluriels et féminin de l’allemand (Schwertern, Mondbrunnens, Dunklen, Magierinnen), nombre et genre de l’espagnol, de l’italien, du portugais et du catalan (Elegida, Cavalieri, Maghi, Dragões), et ailleurs le radical sans ses voyelles finales suivi d’une courte terminaison (Тёмного Лорда, Mieczem).
-
Un volume traduit vers une autre langue ne reçoit plus les termes français de la série. Une décision de série s’imposait à tous les volumes de la série, quelles que soient leurs langues : un volume anglais → allemand recevait « Moonwell → Puits-de-Lune » et était contrôlé dessus, si bien que la bonne traduction allemande était refusée ; reporter un changement de terme sur la série réécrivait aussi le volume allemand (« Die Noyau d’Or. »). Les décisions de série d’une personne ne valent plus que pour les volumes de la paire de langues de la série (sous-tags primaires comparés, comme pour les volumes antérieurs), dans le prompt, le contrôle et la carte Termes appliqués à ce livre, et une propagation ne réécrit que les volumes de la paire du volume d’où elle part.
-
La dérogation d’un volume ne devient plus la convention de la série, et une décision de série l’emporte sur un terme automatique du livre. Un terme qu’un volume avait marqué Déroge à la série était transmis aux volumes suivants comme si la série l’avait décidé, alors que le glossaire de série lui-même l’écarte ; ces volumes gardent désormais la convention de la série. Et une décision de série d’une personne, non verrouillée, perdait face à un terme proposé par l’analyse et accepté automatiquement par le livre, contrairement à l’ordre de priorité documenté : elle l’emporte désormais sur tout terme du livre ni verrouillé ni marqué en dérogation, dans le prompt, le contrôle et la carte Termes appliqués à ce livre.
-
Un glossaire JSON est lu avec des espaces simples, et une source vide est refusée. Un import JSON gardait « Moonwell » entouré d’espaces (un terme introuvable dans le livre, ajouté comme second terme à côté de « Moonwell »), « Red Dragon » avec deux espaces ou une espace insécable, et acceptait une source faite d’une espace. Comme l’étaient déjà les fichiers CSV et TBX, et aussi dans les formulaires de glossaire de l’interface et de l’API, sources et traductions sont désormais gardées sans espaces en bordure et avec des espaces simples ; une source ou une traduction vide est une ligne invalide.
-
Reporter un changement de terme sur le texte traduit ferme les alertes auxquelles il répond. Après le remplacement partout de « Pilule Dorée » par le terme verrouillé « Noyau d’Or », les passages signalés faute de « Noyau d’Or » gardaient leur alerte ouverte, et les points qu’elle coûtait à leur score de qualité. Les alertes « terme verrouillé » de chaque passage réécrit par la propagation sont désormais recalculées sur son nouveau texte : fermées quand le terme y est, reformulées quand un autre terme verrouillé manque encore.
-
Une correction enregistrée avant d’être validée, ou faite dans un passage chinois ou accentué, atteint désormais les volumes suivants. Une correction validée transmet aux volumes suivants de la série ses remplacements (« Seigneur » → « Sire ») avec les noms du passage. Enregistrer puis Valider dans l’éditeur ne retenait rien, la validation étant comparée à la correction enregistrée plutôt qu’à la traduction automatique ; et une source chinoise ou un nom à majuscule accentuée (« Élodie ») ne donnait aucun nom pour reconnaître le passage. La validation est désormais comparée à la dernière version automatique corrigée, les noms sont lus dans toute écriture à majuscules, et une source sans majuscules est reconnue aux noms et alias des fiches du livre. Un passage corrigé deux fois transmet ses remplacements une seule fois.
-
Le pilote automatique ne défait plus les décisions de glossaire d’une personne. Un terme supprimé par une personne revenait avec l’analyse suivante et le pilote automatique l’acceptait de nouveau ; un terme corrigé à la main mais laissé non accepté était supprimé par le pilote automatique comme si l’analyse l’avait proposé ; et une proposition « dragon » rejoignait un « Dragon » verrouillé. Les ajouts, corrections, imports et suppressions de termes du livre par une personne sont désormais inscrits au journal d’audit (
glossary.term_decided,glossary.term_removed) et relus : le pilote automatique ne tranche jamais un terme qu’une personne a ajouté, corrigé ou importé, l’analyse ne repropose jamais un terme qu’une personne a supprimé (elle peut toujours le rajouter), et une proposition est comparée aux termes du livre sans tenir compte de la casse. Aucune migration. -
« Ce que vous corrigez sans cesse » atteint désormais la traduction. Son bouton faisait d’une correction répétée un terme du glossaire dont la source était du texte traduit (« sourit légèrement. ») : un terme n’est donné au modèle que pour les passages dont la source le dit, si bien que la règle n’atteignait jamais un prompt, alors que le guide promettait qu’elle valait pour toute la série. En faire une règle de rédaction ajoute désormais la correction aux Formulations imposées de la fiche de style de la série (ou du livre, hors série ou si la série ne vous appartient pas) : chaque prompt la reçoit avec les consignes (« là où vous écririez “sourit légèrement”, écrivez “esquissa un sourire” »), les volumes de la paire de langues de la série la suivent, et les passages traduits que personne n’a validés qui gardent l’ancienne formulation repassent à réévaluer. La fiche de style liste les formulations imposées et permet de les retirer.
[0.20.0] - 2026-09-26
Notes de mise à jour
- Aucune migration, aucun changement du protocole de licence.
/app/backend/appcontient désormais les fichiers.pycà côté des modules, sans sources.py; les migrations Alembic chargées par chemin restent en.py. Un script qui lit les sources dans l’image doit utiliser le dépôt source. Les traces d’erreur gardent les noms de fichier et les numéros de ligne, mais n’affichent plus les lignes de code.- En qualité maximale, un passage dont la relecture avait déjà commencé sous l’ancien ordre (travail mis en pause ou interrompu pendant la mise à jour) est terminé sans polissage : il n’est pas poli puis relu une seconde fois.
- Aucune migration, aucun changement du protocole de licence. Les prompts intégrés passent en
file-v5+rules-v3: les prompts de relecture de toutes les paires, et tous ceux qui écrivent ou jugent vers le français, changent ; leurs requêtes ne sont donc plus servies par le cache de réponses des versions précédentes. - Aucune migration, aucun changement du protocole de licence. Rien n’est réécrit en base : la typographie ci-dessous est appliquée à chaque sortie d’un livre.
- Pour un livre traduit avant la 0.18, le
sha256de ses chapitres (manifeste du ZIP, résultats de l’API d’automatisation) change une fois, avec son texte. Un résultat déjà enregistré pour une requête d’automatisation terminée reste servi tel qu’il a été enregistré.
Modifié
- L’image publiée ne contient plus les sources Python de
backend/app. La clé de vérification est insérée avant la compilation dans une étape séparée, puis seul le résultat compilé rejoint l’image finale. Les contrôles de l’image vérifient l’absence des sources, les imports, les commandes Python, la clé et les descriptions OpenAPI ; la suite de bout en bout continue de tester l’image construite. - La relecture sait quoi chercher de l’anglais vers le français. Un chapitre traduit, relu, révisé et poli en
maximumpar le même modèle de 27B contenait une double négation, un gérondif mal rattaché (« En marchant dans la rue, la pluie tapote »), des calques (« C’est trop une coïncidence »), des faux amis (random → « aléatoire », though → « d’ailleurs »), un narrateur familier passé à l’imparfait du subjonctif — et aucune correction : « vérifier la grammaire et le registre » ne désigne rien, et un modèle ne voit pas ses propres calques. La relecture finale a même « corrigé » « Tellement. » en « Tellement ennuyé. ». Libris joint maintenant aux prompts qui écrivent ou jugent un passage la liste des fautes qu’un modèle fait sans les voir, avec de courts exemples : celles du français quelle que soit la source, puis celles de l’anglais vers le français (calques, faux amis, anglicismes, aspect progressif). La traduction et la révision les évitent, le polissage les corrige, la relecture, la relecture fusionnée et la relecture finale les cherchent une à une sans proposer de correction qui en commette une, l’arbitrage accepte une proposition qui en retire une et jamais une correction qui en commet une. Les instructions de l’utilisateur et la fiche de style passent avant la liste (un registre soutenu choisi dans la fiche autorise l’imparfait du subjonctif). Les autres paires ne reçoivent rien pour l’instant ; le japonais vers le français reçoit la partie propre au français. Environ 450 tokens par appel d’écriture et 500 à 550 par appel de jugement de l’anglais vers le français, dans le début fixe du prompt que le cache d’un provider peut resservir (#180). - Les relecteurs laissent la typographie française à Libris. Depuis la 0.18, Libris pose lui-même les espaces, apostrophes et points de suspension du français, mais les prompts de relecture demandaient encore de signaler la « typographie de la langue cible » : sur un livre, 9 décisions d’arbitrage portaient sur des apostrophes. Les relecteurs d’un texte français ne les signalent ni ne les corrigent plus et rejettent un point qui ne porte que sur eux ; le choix des guillemets reste relu. Calques, faux amis et tournures non idiomatiques sont nommés comme de vrais problèmes, pas des préférences de style.
Corrigé
-
En qualité maximale, le polissage ne peut plus changer le sens sans que personne le relise (#179). Il suit désormais immédiatement la traduction, avant la relecture et la révision : elles lisent le texte poli et peuvent rétablir un sens qu’il a changé (« Eh, tant pis. » poli en « Eh, merde. »). Il venait en dernier, relu par la seule revue finale. Sa réponse est en outre filtrée avant d’être gardée :
- un paragraphe poli de quatre mots ou plus qui en a perdu plus d’un quart garde son texte précédent (« Je m’ennuie. Tellement incroyablement ennuyé. » réduit à « Je m’ennuie. Tellement. ») ; quand il ne reste rien de ce que le polissage a changé, aucune version n’est enregistrée ;
- un polissage qui ajoute une erreur des contrôles automatiques (terme verrouillé perdu, texte resté dans l’écriture de la source) est refusé en entier, comme une révision de la revue finale.
Chaque refus figure au journal des décisions (étape
translation,polishing,rejected). Un travail de relecture ne polit plus, et l’estimation du coût suit le nouvel ordre. -
Un passage qui ne laisse plus de place à ses voisins est traduit par parties sur une petite fenêtre, comme un passage trop long, au lieu d’échouer sur « trop petite pour garder le voisinage du passage » ; l’arbitrage prend alors son contexte réduit.
-
Les livres traduits avant la 0.18 sortent désormais avec la typographie française, à l’export et dans le lecteur. La 0.18 compose ce qu’écrit la machine, mais un livre terminé n’est plus jamais réécrit : un livre traduit sous la 0.17 gardait ses apostrophes droites — mêlées de courbes dans les phrases retouchées par l’arbitrage — et des espaces ordinaires avant ; : ! ?. Chaque sortie compose maintenant les passages de la machine au moment de les lire (
delivered_unitsetdelivered_textdansapp/engines/typography.py) : EPUB traduit, partiel et bilingue, TXT, ZIP de chapitres, Markdown, Word, export d’un chapitre, exports par lot (textes ou EPUB d’une série), publication en bibliothèque, envoi par courriel et WebDAV, résultats de l’API d’automatisation et outil MCPexport_book, lecteur intégré, liens de relecture et aperçu d’un chapitre. L’éditeur, les champs de correction du lecteur et les archives de projet et de série, qui restaurent une base, gardent le texte enregistré. Le texte d’une personne et un original conservé sortent tels quels ; dans le Word, un passage corrigé et la version du modèle à laquelle il est comparé gardent la même typographie, pour qu’aucune révision n’apparaisse que personne n’a faite. Une langue sans règle ne change pas, et un livre déjà composé sort à l’identique. (#184) -
Les exports texte d’un volume EPUB gardent leurs espaces insécables. Remettre un paragraphe sur une ligne prenait U+00A0 pour une espace ordinaire, ce qui défaisait la typographie des livres traduits avec la 0.18 en TXT, en Markdown, dans le ZIP de chapitres, l’EPUB bilingue et les résultats de l’API d’automatisation.
[0.19.1] - 2026-09-26
Notes de mise à jour
- Aucune migration ni modification de requête. Le serveur de licences 0.12.0 envoie
trial_already_used; les versions précédentes restent compatibles.
Modifié
- Le refus d’un essai demandé sur le site, sur une machine ou une base ayant déjà activé un autre essai demandé sur le site, affiche désormais un message précis en français et en anglais, avec les formules et le contact du support. Ce refus n’invalide pas un certificat déjà enregistré.
[0.19.0] - 2026-09-26
Notes de mise à jour
- Aucune migration, aucun changement du protocole de licence : compatible avec le serveur de licences déployé (0.11.0).
- Une question posée sur un passage exige désormais une licence valide ; sans elle, la réponse est
402 {"code": "licence"}.
Corrigé
- Une question posée sur un passage exige désormais une licence, comme tout autre appel au modèle. Posée depuis
l’éditeur, hors de tout travail, elle atteignait le modèle sans que la licence soit vérifiée. Elle suit maintenant la
règle d’un lancement (licence valide, ou quota atteint sur un livre dont les mots sont déjà comptés) et reçoit
sinon
402 {"code": "licence"}, le refus d’une reprise.
[0.18.1] - 2026-09-26
Notes de mise à jour
- Aucune migration, aucun changement du protocole de licence.
AUTOPILOT_ESCALATE_AFTERetAUTOPILOT_ESCALATE_WINDOWn’existent plus ; laissées dans un.env, elles sont ignorées.
Modifié
- Le pilote automatique poursuit après les réponses invalides du modèle. Après épuisement des essais de
traduction, il conserve le meilleur texte disponible, ou l’original avec un avertissement. Une analyse,
amélioration, vérification de cohérence, relecture finale ou décision d’arbitrage incomplète ne bloque plus
les étapes suivantes. Le rapport et l’interface comptent les originaux conservés, points ouverts, contrôles
non conclus et lacunes d’analyse. Les livraisons API gardent le statut d’avertissement et
complete=falsepour ces points ; l’indisponibilité du modèle garde son mécanisme de secours et de reprise. - Un passage sur lequel le modèle du livre échoue cinq fois a deux essais sur le modèle supérieur, puis revient au modèle du livre ; les passages voisins ne le quittent jamais (règle du propriétaire). Cinq refus, réponses jamais valides ou erreurs sur un passage dans un travail — un appel interrompu par une pause ne compte pas — envoient ses appels suivants au modèle supérieur, deux au plus, consignés avec le passage. Cela s’ajoute aux passages qui reviennent à l’arbitrage et à l’échelon « modèle supérieur » de la récupération.
- Le modèle supérieur est réservé aux cas difficiles. Après trois échecs sur cinq appels d’une étape, il reprenait toute cette étape jusqu’à la fin du travail — toutes les traductions du livre, ou toutes les relectures, au prix du modèle supérieur, et avant les providers de secours. Aucune étape du livre ne bascule plus sur lui. Il arbitre un passage qui revient à l’arbitrage IA (un tour précédent l’a arbitré et ses points sont de nouveau ouverts : une réponse jamais valide, une erreur que son texte porte encore) — un premier arbitrage revient toujours au modèle du livre — et il traduit toujours un passage qu’aucun échelon de la récupération n’a pu traduire. Chaque recours est consigné avec son passage ; un modèle supérieur en panne renvoie le passage au modèle du livre. Réglages, API et textes de l’interface le disent.
[0.18.0] - 2026-09-26
Notes de mise à jour
- Aucune migration de base de données ni modification du protocole de licence. La typographie française est appliquée aux textes écrits par la machine lors de leur prochaine réécriture ; les traductions existantes restent inchangées.
- Un travail du pilote automatique se bloque si la traduction, la cohérence, la relecture finale ou l’arbitrage demeure incomplet. Corriger le provider ou les points restants, puis reprendre le travail ; les étapes terminées sont conservées.
Modifié
- La typographie française est appliquée à ce qu’écrit la machine. Sur 2 980 passages traduits, 77 % avaient une
espace ordinaire avant ; : ! ? ou », 71 % après «, 542 après le tiret qui ouvre une réplique, et les livres mêlaient
apostrophes droites et courbes : le prompt le demande, le modèle l’oublie, et la liseuse coupe alors la ligne avant
un point d’interrogation. Chaque écriture de la machine (
save_version) pose désormais une espace insécable (U+00A0, présente dans toutes les polices de liseuse) avant ; : ! ?, à l’intérieur des « » et après un tiret de dialogue, l’apostrophe ’ et les points de suspension … (app/engines/typography.py). Seule une espace déjà là devient insécable, sauf à l’intérieur des guillemets ; aucun mot ni marqueur de mise en forme ne change. Le texte d’une personne est gardé tel qu’elle l’a tapé ; les passages déjà traduits changent à leur prochaine réécriture. - La règle typographique jointe aux prompts s’efface devant la fiche de style : une fiche qui demande des tirets de
dialogue ou des guillemets anglais n’est plus contredite par « guillemets « » pour les dialogues » (règles
rules-v2).
Corrigé
- Un alias en commun ne fait plus de deux personnages un seul. L’analyse rattachait un nouveau personnage à toute fiche partageant un seul nom avec lui, et fusionnait les fiches vers lesquelles pointaient deux de ses noms : Lily Potter était absorbée par Harry Potter à cause de « Potter » (et prenait son genre : tous ses accords devenaient faux), la reine Elara par le roi Aldric à cause de « Votre Majesté ». Un personnage ne rejoint plus une fiche que par son propre nom ou par le nom canonique de la fiche, dans la mémoire écrite comme dans l’analyse parallèle ; un nom que portent deux fiches ne désigne plus aucune des deux, l’alias partagé est proposé sous « Identités à rapprocher ? », et deux fiches aux genres connus différents ne sont jamais fusionnées sans une personne. Il en va de même pour les personnages d’une Bible ou d’une analyse enregistrées par une personne.
- L’arbitrage du pilote automatique ne clôt plus un point qu’il n’a pas traité. Une réponse qui ne tranchait rien fermait tous les points ouverts comme rejetés et le passage sortait vert ; une critique acceptée pouvait laisser son paragraphe inchangé, un autre paragraphe pouvait être réécrit, et un paragraphe réduit à la seule phrase corrigée était appliqué. Une réponse doit désormais trancher chaque point une fois, modifier le paragraphe de chaque correction qu’elle accepte et aucun autre, garder 60 % de chaque paragraphe corrigé et ne jamais le remplacer par une consigne. Une réponse qui n’y parvient pas après ses essais laisse les points ouverts pour le tour suivant au lieu de les fermer, et une erreur encore présente dans le texte (un terme verrouillé absent) est relevée de nouveau après son rejet. Les propositions portent désormais au modèle leur gravité et leur paragraphe.
- La relecture fusionnée n’annule plus une modification faite pendant son appel. Sa révision était écrite sur le passage relu après la réponse du modèle : un terme propagé entre-temps devenait la révision de base, puis était écrasé par une révision de l’ancien texte. Elle est désormais écrite sur la révision que le modèle a lue, comme la révision séparée ; la version périmée reste dans l’historique.
- Un passage traduit en plusieurs parties garde l’espace entre ses phrases (petites fenêtres de contexte, et l’échelon de récupération qui traduit phrase par phrase). Les parties d’un paragraphe étaient recollées telles que le modèle les rendait (« froide.Elle attendit »). Elles sont jointes par une espace (un retour à la ligne là où la source revenait à la ligne) dans les langues qui espacent leurs phrases, et se touchent en japonais, en chinois ou en thaï.
- L’échelon « contexte réduit » de la récupération garde la fiche de style et les consignes du chapitre. Il n’envoyait que les consignes du livre et du passage : un passage récupéré (ou un arbitrage sur une petite fenêtre) pouvait vouvoyer là où la fiche tutoie, ou quitter le temps du récit du livre.
- Le contrôle des dialogues de la fiche de style ignorait les romans anglais. Un guillemet employé par la source n’était jamais reproché à la traduction : les guillemets droits gardés d’un roman anglais n’étaient donc jamais signalés. Ils le sont désormais quand ce sont les seuls guillemets de la traduction ; à côté des guillemets de la fiche, ils restent lus comme une citation à l’intérieur de la réplique.
- Remplacer un terme dans tout un livre, et placer les notes du traducteur, le trouvent qu’il soit écrit avec une apostrophe droite ou courbe.
- Les termes verrouillés suivent la grammaire de toute langue cible, pas seulement du français. Le contrôle, qui refuse une traduction (trois essais, puis le passage échoue), n’acceptait que des terminaisons françaises : des traductions justes étaient refusées en coréen (마법사는), en russe (Тёмного Лорда), en allemand (Schwertern), en espagnol (Elegida), en arabe (بالسيف), et en français même (Gardienne, Maîtresse, Blanche, « Coeur » pour « Cœur »). Le français et l’anglais connaissent désormais leurs féminins et pluriels (Sorcière, Actrice, Ladies, Elves), une autre langue garde le début du mot et laisse varier sa fin, et un terme d’une écriture sans espaces est trouvé collé à ses voisins. Un terme chinois ou japonais d’un seul caractère (王 est aussi dans 王国, « royaume ») est signalé, jamais refusé.
- Les noms coréens, thaïs, khmers et birmans sont trouvés dans le texte. Un nom suivi d’une particule (민수는) n’était jamais « mentionné » : son terme de glossaire, sa fiche et son identité de série manquaient au prompt, le pilote automatique ne comptait aucune occurrence de ses termes, et les termes verrouillés n’étaient pas contrôlés. Une seule définition des écritures sans espaces sert désormais au contexte, aux contrôles et à la propagation des termes ; un nom en katakana ne se trouve plus à l’intérieur d’un mot plus long (リン dans リンゴ).
- Les longueurs se comparent quelle que soit l’écriture. La longueur d’une traduction se comparait caractère par caractère : les passages chinois → français sortaient des bornes 93 % du temps (une alerte, −15 et un appel de relecture chacun) et l’anglais → japonais ou coréen perdait 5 points deux fois sur trois, tandis qu’une omission depuis le japonais passait inaperçue. Les longueurs se mesurent désormais en lettres d’un alphabet (un caractère Han pèse 4, un kana 1,6, une syllabe hangul 2,3) : sur des traductions humaines, les alertes tombent à 0–0,4 % pour toutes les paires, anglais → français inchangé.
- Un texte resté dans l’écriture de la source est signalé (
untranslated, une erreur) : du japonais laissé dans une traduction française, y compris un passage recopié tel quel, que le contrôle « texte identique » manquait faute d’espaces pour compter les mots. Aucun n’a été levé sur 58 000 segments traduits par des humains ; un roman anglais qui cite un panneau japonais le garde. - Le verdict d’une relecture finale survit à l’échec de sa correction. Quand le relecteur trouvait des erreurs et que la révision censée les corriger échouait (refus, réponses invalides), toute la relecture était perdue : le passage restait « ok », noté 100, et n’était jamais arbitré ; avec des providers de secours, la relecture était en plus repayée sur chacun. Le verdict est désormais appliqué tel quel — ses points restent ouverts pour l’arbitrage — et l’échec est journalisé avec sa raison, comme une relecture qui échoue partout (sa raison n’était que le nom d’une exception).
- Le pilote automatique termine chaque étape avant la suivante : une traduction, une vérification de cohérence, une revue finale ou un arbitrage encore en échec bloque le travail avec sa raison. Les étapes de relecture et de cohérence essaient les providers de secours configurés ; une reprise redemande seulement le travail échoué.
- La formule s’appelle « Personnelle » dans Paramètres › Licence, comme sur le site et au serveur de licences.
[0.17.1] - 2026-09-26
Notes de mise à jour
- Aucune migration. Rien n’est recompté : le compteur du cycle reste celui de la 0.17.0.
Corrigé
- L’estimation d’import promet exactement ce que l’ajout accepte. Au-delà du quota, elle ne ramenait plus le reste à
0 avant d’ajouter la marge (quota 100 000, 110 000 utilisés : elle annonçait 20 000 mots au lieu de 10 000), et elle
ignorait le quota mensuel propre au compte. Un seul calcul sert désormais aux deux (
app/licence/charge.py,room) ; l’estimation renvoieroometaccount_room, et l’assistant dit quel quota bloque. - Un cycle dont le report a tout pris limitait mal les ajouts : son quota affiché vaut 0, et un livre était accepté comme s’il n’y avait pas de limite. Seule la marge reste alors disponible.
- Messages de refus : les nombres sont écrits de la même façon pour la licence et pour le compte.
librisctlreconnaît une installation faite par l’installateur (/opt/libriset leLIBRIS_PROJECTde son.env) quand l’ancien/opt/libris-productionn’existe pas.- Documentation : l’API (FR/EN), l’OpenAPI (
allowance_insufficient, 402 à l’import), l’exploitation et l’architecture décrivent le comptage à l’ajout de la 0.17 ; commentaire de la CI sur CT117 corrigé.
[0.17.0] - 2026-09-26
Notes de mise à jour
- Un livre est compté dès qu’il est ajouté. Aucune migration, et rien n’est recompté à la mise à jour : le compteur du cycle repart du nombre qu’il avait. Les livres déjà présents restent comptés comme avant, passage par passage au fil de leur traduction ; seuls les livres et chapitres ajoutés ensuite le sont d’un coup.
Modifié
- Les mots d’un livre sont comptés à son ajout, et non plus passage par passage au fil de la traduction :
tous ses mots, même s’il est supprimé ensuite sans avoir été traduit. Vaut pour l’assistant d’import, l’API
d’automatisation, le MCP, les sources suivies, la restauration d’une archive et la seconde langue ; un
chapitre ajouté ou remplacé ensuite compte seulement ses nouveaux passages (
app/licence/charge.py). - Un livre est accepté tant qu’il tient dans ce qui reste du quota du cycle plus la marge
LICENCE_QUOTA_OVERRUN_WORDS(20 000 mots) ; au-delà, il est refusé en entier (402 licence_quota_insufficient, ouallowance_insufficientpour le quota mensuel d’un compte) et rien n’est compté ni créé. L’estimation d’import le dit avant l’import (margin), et l’assistant désactive alors les trois boutons d’import. - Un livre déjà compté se traduit, se relance et se corrige sans plus rien coûter, même une fois le quota atteint ; seule la comparaison de providers, qui appelle les modèles en plus, reste comptée et arrêtée par le quota.
[0.16.4] - 2026-09-25
Notes de mise à jour
- Les images passent à
registry.libris-translate.com/libris/libris. Le projet GitLab a quitté le groupedevpour le nouveau groupelibris, et le registre suit le projet :registry.libris-translate.com/dev/librisne sert plus aucune image. Mettez à jour avec l’installateur du site (curl … https://libris-translate.com/install.sh | sudo bash) : il télécharge depuis le nouveau chemin et réécrit lesLIBRIS_IMAGEetLIBRIS_CODEX_IMAGEépinglés de.env. Les identifiants de registre d’une licence ne changent pas. Une installation qui épingleLIBRIS_IMAGEà la main, ou une copie des sources qui utiliseLIBRIS_REGISTRY, doit indiquer elle-même le nouveau chemin.
Modifié
- Nouveau chemin des images. L’installateur, le fichier Compose,
.env.exampleet la documentation nommentregistry.libris-translate.com/libris/libris(:latest,:X.Y.Z,:codex-X.Y.Z).
Corrigé
- Une mise à jour ne s’arrête plus sur une image installée qu’aucun registre ne sert plus. L’installateur
échouait avec « could not download the installed image » quand cette image n’était ni sur l’hôte ni
téléchargeable (l’ancien chemin
dev/libris, une image supprimée). Il compare désormaisdocker-compose.ymlau seul nouveau modèle : un fichier identique est remplacé, tout autre est gardé, le modèle est déposé à côté sousdocker-compose.yml.libris-new, et la même commande reprend une fois la fusion faite.
[0.16.3] - 2026-09-25
Notes de mise à jour
- Le projet Compose s’appelle désormais
libris. La prochaine mise à jour par l’installateur arrête Libris le temps de copier les volumesepub-translator_*(base, livres, état Codex, journal) dans des jumeauxlibris_*, vérifie chaque copie, retire les anciens conteneurs et l’ancien réseau, puis enregistreLIBRIS_PROJECT=librisdans.env. Il faut la place d’une copie supplémentaire des données ; sinon l’installateur gardeLIBRIS_PROJECT=epub-translatoret indique comment réessayer. Les anciens volumes ne sont jamais supprimés : l’installateur affiche la commandedocker volume rmà lancer une fois le nouveau nom éprouvé. Une copie des sources mise à jour parscripts/deploy.shgardeepub-translatortant que son.envne nomme pas de projet.
Modifié
- Plus d’
epub-translatorsur une nouvelle installation. Les conteneurs s’appelaient déjàlibris-*, mais le projet Compose, son réseau et ses volumes portaient encore le nom du prototype d’origine. Ils deviennentlibris,libris_defaultetlibris_database,libris_books,libris_codex-state,libris_logs; l’installateur et.env.exampleécriventLIBRIS_PROJECT=libris, le paquet Python s’appellelibriset les images localeslibris:localetlibris:rollback. La racine OpenViking (viking://resources/epub-translator) ne change pas : elle désigne des documents déjà publiés.
[0.16.2] - 2026-09-25
Notes de mise à jour
- Aucune migration de base. Rien à faire au-delà de la mise à jour habituelle ; la revue finale garde désormais les corrections qui améliorent un passage, donc un livre relu à nouveau peut voir plus de passages réécrits (toujours « à vérifier » quand une remarque subsiste).
Modifié
- La revue finale garde une correction qui améliore un passage, pas seulement une correction parfaite.
Une révision n’était appliquée que si la seconde lecture ne signalait plus rien du tout : la moindre
remarque restante faisait jeter toute la correction. Sur une série de 17 volumes, 40 révisions qui
supprimaient des erreurs ont été abandonnées en une passe, et leurs passages sont restés « à vérifier »
sans changement. Une révision est désormais appliquée si elle n’ajoute aucune erreur des vérifications
automatiques et laisse moins d’erreurs, ou autant d’erreurs et moins d’autres remarques ; ce que la
seconde lecture signale encore reste sur le passage, toujours à vérifier
(
app.engines.translation.final_review.improves).
Corrigé
- Les pluriels irréguliers d’un terme verrouillé sont reconnus. « Evil Eyes » traduit « Yeux maléfiques » échouait sur le terme verrouillé « Evil Eye → Œil maléfique », et la correction demandée par la relecture était refusée (« glossaire verrouillé non respecté ») : aucune traduction ne pouvait satisfaire les deux. Le contrôle accepte désormais les pluriels irréguliers œil → yeux, ciel → cieux, aïeul → aïeux, et -al → -aux (« Général » → « Généraux »).
[0.16.1] - 2026-09-25
Notes de mise à jour
- Une migration de base,
59edaaf5b59b: elle marque seulement comme périmés les scores de passage qui comptaient des appels échoués ou des arbitrages ; ils sont recalculés à la prochaine ouverture de la qualité ou de l’éditeur du livre. Sauvegardez d’abord la base, comme pour toute version avec migrations. - Le nom affiché devient « Libris Translate » : titres de fenêtre et d’onglet, courriels, titre
OpenAPI. L’émetteur des codes d’authentification (TOTP) et le nom WebAuthn par défaut
(
WEBAUTHN_RP_NAME) changent pour les nouveaux enrôlements seulement : les codes et clés déjà enregistrés gardent leur ancien libellé et continuent de fonctionner ; unWEBAUTHN_RP_NAMEexplicite dans.envest conservé. Les identifiants techniques (libris,LIBRIS_*, images,librisctl) ne changent pas. - Le serveur de licences 0.8.1 ou ultérieur est recommandé : les messages de refus suivent ses codes, et une installation qui n’a jamais signé enrôle sa clé quand il exige les signatures. Avec un serveur de licences plus ancien, les codes inconnus affichent le message du serveur lui-même.
Modifié
- Un passage corrigé n’est plus classé sous un passage intact. Le score de qualité d’un passage ne le
pénalise plus pour son historique : les appels au modèle échoués avant une traduction qui passe les
contrôles (
retry, 3 points chacun, jusqu’à 12) et les critiques appliquées ou acceptées par l’arbitrage (arbitration, 3 points chacune) ne coûtent plus rien ; une critique rejetée (2) ou reportée (4) compte toujours. Sur une série de 17 volumes, 150 des 234 passages hors de la bande « bon » n’y étaient que pour ces raisons, alors que le pilote automatique les avait corrigés. Les deux signaux restent enregistrés. - Documentation : cohérence avec le serveur de licences et le site. La procédure de publication de
docs/development.mdne décrit plus de déploiement au tag : un tag publie les images et la release GitLab et ne déploie rien ; les clients installent et mettent à jour depuisregistry.libris-translate.comavec l’installateur, et le/version.jsondu site est ce que le serveur de licences annonce.docs/operations.mddit la même chose du script de déploiement de production. - Ce que donne une formule (
docs/configuration.fr.md#licence, et son pendant anglais) : comptes, machines (une place libérée au bout de sept jours,move_too_soon), API d’automatisation et partage (Studio et Pro seulement,402 automation_not_licensed/sharing_not_licensed), quota du cycle ; la limite de mots par compte reste au mois civil ; le certificat se renouvelle toutes les heures et vaut 72 heures. - Le guide Docker (FR et EN) gagne une étape Activer la licence et cite le pont Codex que démarre
l’installateur ; lignes de dépannage pour les refus de licence dans
docs/operations.md. - L’aide passe par support@libris-translate.com ; les signalements de sécurité vont toujours à
licences@libris-translate.com avec
[SECURITY], accusés sous deux jours ouvrés (SECURITY.md). Le produit s’appelle Libris Translate à sa première mention. .env.example: les commentaires suivent le cycle de quota, et les exemples SMTP ne nomment plus de vrais hôtes.- Le produit s’appelle Libris Translate partout où il se nomme (décision du propriétaire ; le site le
fait déjà). Règle : le nom complet dans chaque titre et à chaque première mention — titres de fenêtre et
d’onglet (
… · Libris Translate), barre latérale et en-tête mobile (« Libris » avec « Translate » dessous), page de connexion, écran de chargement, bandeau de mise à jour, titres des cartes « Quitter » et « Utilisateurs », courriels (objets, première mention, signature « — Libris Translate »), titres FastAPI et OpenAPI (« Libris Translate automation API »,docs/openapi/libris-v1.jsonrégénéré) etserverInfo.titleet instructions du serveur MCP. « Libris » seul reste admis ensuite, dans un texte d’un écran qui affiche déjà le nom. La valeur par défaut deWEBAUTHN_RP_NAMEet l’émetteur des nouveaux codes d’authentification deviennent « Libris Translate » (clés et codes déjà enregistrés continuent de fonctionner). Les identifiants techniques ne changent pas :dev/libris,librisctl,LIBRIS_*,X-Libris-*,.libris-*, noms d’images et de fichiers d’export,serverInfo.nameMCP (libris), clés i18n.
Corrigé
- Un terme verrouillé accordé au féminin n’est plus signalé absent. Le contrôle du glossaire verrouillé
acceptait le pluriel d’une traduction verrouillée mais pas son féminin : « Souveraine de la sagesse »
échouait sur « Ruler → Souverain », levait une alerte d’erreur, et une correction écrite ainsi était
refusée (« glossaire verrouillé non respecté »). Le contrôle accepte désormais l’accord en
-e. - Les refus de licence disent pourquoi, dans la langue de l’interface. La réponse à l’activation
attendait des codes qu’aucun serveur de licences n’a jamais envoyés (
revoked,expired,too_many_instances) et retombait sur « refusée » pour les vrais. Chaque code du serveur de licences 0.8.1 a désormais son propre message en français et en anglais (app.licence.REFUSALS) : clé inconnue, licence révoquée, suspendue ou expirée,move_too_soon, les refus de signature (signature_required,bad_signature,malformed_signature,no_public_key,replayed,clock_skew),too_many_attemptsetregistry_unavailable. Un code que cette version ne connaît pas encore affiche le message du serveur en français, et nomme le code en anglais plutôt que d’afficher des mots français. Paramètres › Licence donne la raison d’une licence refusée au renouvellement au lieu de « refusée », et affiche le dernier refus d’une licence toujours en vigueur (horloge décalée, rapport reçu deux fois). Les refus qui coûtent le certificat (INVALID) ne changent pas. - « Quota de mots du mois atteint » devient « Quota de mots du cycle atteint. » (EN “This cycle’s word
quota has been reached.”). Le
stop_reasondes travaux qu’il met en pause restelicence, et un travail arrêté par une version précédente se lit toujours en anglais. Le réglage de notification dit désormais « À 80 % du quota du cycle ». - La formule s’affiche par son nom dans Paramètres › Licence : Essai, Personnel, Studio, Pro (EN Trial,
Personal, Studio, Pro) au lieu de
trialoupersonal; une formule que cette version ne connaît pas garde son identifiant. - Le refus d’un compte au-delà des sièges de la licence donne support@libris-translate.com au lieu de « écrivez-nous ».
- Une installation qui n’a jamais signé enrôle sa clé quand le serveur de licences exige les signatures.
Un Libris activé avant l’arrivée des signatures (0.10 ou antérieur) n’a pas de paire de signature — un
battement de cœur n’en tire jamais — et ses rapports partent sans signature ; avec un serveur de licences
réglé sur
SIGNATURES_REQUIRED=true, chaque renouvellement répondaitsignature_requiredet l’installation s’arrêtait à l’expiration de son certificat de 72 heures. Un renouvellement traite désormaissignature_requiredcomme il traitait déjàno_public_key: une activation avec la clé enregistrée, qui tire et enrôle une paire. Si cette activation est refusée, c’est sa raison qui est gardée (une licence révoquée coûte toujours le certificat ;bad_signature, quand le serveur garde la clé d’une paire perdue avec unSECRET_KEYchangé, le garde et renvoie au support), jamais une boucle. - Une requête que le serveur de licences n’a pas pu lire (le 422 de FastAPI, dont le
detailest la liste d’erreurs de Pydantic) était stockée brute et affichée telle quelle dans Paramètres › Licence. Elle est désormais nomméeinvalid_request, avec un message lisible (FR/EN) et les champs en cause ; elle ne coûte toujours pas le certificat (INVALIDinchangé). - Le refus
move_too_soondonne la règle du serveur de licences : une machine ne cède sa place qu’après 7 jours sur la licence. - « Quota du mois » devient « cycle de quota » là où il s’agit de la licence : description de l’outil MCP
licence_status, aide des mots par compte dans Paramètres › File d’attente (cette limite reste, elle, au mois civil) et commentaires du code. - Documentation (
docs/configuration.md,docs/configuration.fr.md,docs/user-guide.fr.md) : « une licence, une installation » et « douze endroits » laissent place aux machines de chaque formule (essai 2, Personnel 3, Studio 5, Pro 10) et à la règle de déménagement après 7 jours ; le guide cite le message actuel demove_too_soon; un certificat perpétuel est sans limite de mots plutôt que « sans limite mensuelle ». - Les messages nomment les écrans comme l’interface : « Aucune licence activée. Saisissez votre clé dans Paramètres › Licence » (au lieu de Réglages), le refus du quota par compte renvoie à Paramètres › File d’attente, et la documentation du serveur MCP à Mon compte › Jetons d’API. Les travaux arrêtés par une 0.16.0 avec l’ancien libellé se lisent toujours en anglais. Une clé de traduction morte (« Tester la connexion ») quitte l’écran des providers.
SECURITY.md: les versions couvertes sont la dernière publiée et la précédente, comme le disaient déjà son texte et le site (le tableau ne citait que la dernière).
[0.16.0] - 2026-09-25
Notes de mise à jour
- Deux migrations de base de données :
d0d68575c19aélargitlicence_usage.periodpour nommer un cycle de quota (AAAA-MM-JJ) autant qu’un mois civil, ete7c1a4b9d352ajoute trois colonnes àwebdav_connectionspour l’envoi automatique. Sauvegardez d’abord la base, comme pour toute version avec migrations. Annuler la première supprime les lignes de cycles (le serveur de licences garde son propre décompte). - Les cycles de quota demandent le serveur de licences 0.8.0. Avec lui, le quota de mots se renouvelle à la date anniversaire de l’abonnement et un dépassement est déduit du cycle suivant ; avec un serveur de licences plus ancien, rien ne change : mois civil, sans report. Libris et le serveur de licences se mettent à jour dans n’importe quel ordre.
- Un livre qui ne tient pas dans ce qui reste du quota est refusé avant d’entrer dans la file
(
licence_quota_insufficient,402). Les scripts d’automatisation qui lancent des livres par l’API ou le MCP doivent traiter ce code ; le livre reste importé et pourra être lancé à l’ouverture du quota suivant. - Le certificat perpétuel de fin d’activité est accepté à partir de cette version. Rien à faire aujourd’hui : il ne serait envoyé que si l’éditeur cessait son activité, et s’installe dans Paramètres › Licence › Certificat perpétuel.
- L’envoi automatique Nextcloud / WebDAV est désactivé pour toutes les connexions existantes : activez-le connexion par connexion dans Mon compte › Connexions Nextcloud / WebDAV.
- Les licences Essai et Personnel perdent l’API d’automatisation, le MCP et le partage (voir Sécurité
ci-dessous) ; jetons et liens sont conservés. Relancez l’installateur plutôt qu’un simple
docker compose pull: une installation restée sur un ancien fichier Compose est désormais signaléeoutdated(#163).
Ajouté
-
Le certificat perpétuel de fin d’activité de l’éditeur est accepté (#177, dev/libris-licence#29). Si l’éditeur cesse son activité, chaque licence valide reçoit un certificat signé avec la même clé que le certificat horaire (
v: 2,kind: perpetual,reason: end_of_activity), sans date d’échéance, sans machine et sans limite mensuelle de mots, lié à la clé de licence parkey_sha256(l’empreinte de la clé normalisée comme le fait le serveur de licences). Libris ne l’accepte qu’avec la clé de licence pour laquelle il a été signé — saisie en majuscules ou minuscules, avec ou sans tirets — et sur n’importe quelle machine : une réinstallation ou une sauvegarde restaurée continue de fonctionner. Un administrateur l’installe dans Paramètres › Licence › Certificat perpétuel (le coller ou choisir le fichier.libris-certificate, et donner la clé si elle n’est pas enregistrée), avecpython -m app.licence.perpetualdans le conteneur de l’API, ou parPOST /api/settings/licence/certificate; l’opération est inscrite au journal. Dès lors, plus rien n’est demandé au serveur de licences (ni renouvellement, ni rapport, ni libération), aucune réponse ne peut retirer le certificat — pas même une révocation déjà en route —, le travail est autorisé sans échéance (« Licence perpétuelle (fin d’activité de l’éditeur) »), aucun quota mensuel n’est appliqué et aucun avertissement de renouvellement en retard n’est envoyé ; comptes, API d’automatisation et partage suivent sesfeaturescomme avec le certificat horaire. Activer une autre clé le remplace toujours. Tout autrev: 2est refusé, et un certificatv: 1sans date d’échéance reste expiré.GET /api/settings/licencegagneperpetual. Contrôle inter-dépôts :scripts/audit_perpetual_contract.pylit, dans des processus séparés, ce que signescripts/end_of_activity.pydu serveur de licences. -
Le quota de mots suit le cycle de l’abonnement, et le dépassement d’un cycle est déduit du suivant (dev/libris-licence#32, #33). Avec un serveur de licences qui compte en cycles, le quota se renouvelle à la date anniversaire de l’abonnement et non le premier du mois, et les mots traduits au-delà du quota d’un cycle — la marge qui laisse finir le livre en cours — sont déduits du cycle suivant, une fois. Libris compte ses mots dans le cycle que nomme le certificat, rapporte les derniers mots d’un cycle terminé à ce cycle et applique ce que le cycle autorise réellement. Paramètres › Licence affiche les mots du cycle, la date du nouveau quota et le report éventuel. Avec un serveur de licences plus ancien, rien ne change : mois civil, sans report. L’activation et le battement de cœur envoient désormais
period, qu’un serveur plus ancien garde comme un champ inconnu, signé comme les autres. -
Un livre dont les mots dépassent ce qui reste du quota n’entre pas dans la file (#176). Quel que soit le chemin — assistant d’import, page du livre, démarrage d’une série (chaque volume doit tenir dans ce que les précédents ont laissé), API d’automatisation, MCP, sources suivies —, un livre dont les mots restant à traduire dépassent ce qui reste du cycle est refusé avant d’être mis en file, avec un message clair et le code stable
licence_quota_insufficient(402surPOST /api/projects/{id}/jobset l’outil MCPstart_job;stop_reasond’une demande d’API en échec ;coded’un volume refusé au démarrage d’une série). Il peut toujours être importé et analysé. L’assistant d’import le dit avec la date du nouveau quota et désactive Importer et lancer tout le pipeline. Seuls comptent les passages pas encore décomptés : la suite d’un volume ne coûte que ses nouveaux chapitres ; la marge de 20 000 mots termine un livre, elle n’en fait jamais entrer un ; une licence sans limite ne refuse jamais. -
Les administrateurs apprennent qu’une nouvelle version de Libris est publiée (#166). Le serveur de licences peut annoncer la dernière version dans un champ facultatif
latest_versionde ses réponses d’activation et de heartbeat horaire (serveur de licences avecLIBRIS_LATEST_VERSIONrenseigné) ; rien de nouveau ne lui est envoyé. Quand cette version est plus récente que celle qui tourne, les administrateurs — et personne d’autre — voient un bandeau discret : « Libris X.Y.Z est disponible », un lien vers le journal des modifications sur libris-translate.com, la commande de l’installateur (et celle qui fixeLIBRIS_TAG=X.Y.Z), et un rappel : sauvegarder puis mettre les livres en cours en pause. Chaque administrateur peut le masquer pour cette version ; la suivante est annoncée de nouveau. Rien n’est jamais mis à jour automatiquement. Un serveur de licences plus ancien, ou injoignable, n’annonce rien. API :GET /api/installation/update,POST /api/installation/update/dismiss. -
Blocs de code colorés, un seul pour toute l’interface (#175). La documentation intégrée et les écrans qui montrent une commande, une configuration ou une réponse JSON (exemple d’API de Mon compte, commande de mise à jour de Codex, tests de connexion et de mémoire, rapport de validation à l’import, fusions de personnages, détail des requêtes au modèle) partagent un même bloc de code : un panneau encre dans les deux thèmes, le langage nommé, un bouton Copier qui copie le texte brut, le défilement au clavier et la coloration de bash, JSON, YAML, Python, HTTP et dotenv/INI/TOML. Les couleurs sont les jetons
--syntax-*partagés avec le site, chacun au niveau WCAG AA sur le fond du code en Papier et en Nuit, et cèdent la place aux couleurs du système en mode contrastes forcés. La coloration dessine des éléments, jamais du HTML, et n’ajoute aucune dépendance. Le code en ligne a le même aspect partout et les longues valeurs (jetons, adresses, empreintes) passent à la ligne sur téléphone ; un bloc de code indenté sous un élément de liste de la documentation s’affiche désormais comme un bloc. -
Les pannes d’OpenViking sont visibles, et les événements en erreur repartent seuls (#165). Réglages › Mémoire · OpenViking a une carte État d’OpenViking : joignable ou non (le worker vérifie chaque minute), les événements en attente et en erreur, la dernière erreur et les plus fréquentes, le prochain essai, et Relancer les événements en erreur. Un passage de joignable à injoignable, ou l’inverse, est inscrit une fois au journal ; quand OpenViking revient, ses événements en erreur sont remis en file aussitôt. Le même état forme l’élément
openvikingdeGET /health, pour un administrateur ou pour tous avecPUBLIC_HEALTH_DETAILS=true, comme les vérifications de configuration ; une panne d’OpenViking ne fait jamais échouer le contrôle de santé. -
Nettoyage quotidien facultatif des vecteurs orphelins d’OpenViking (#165). À côté de la recherche quotidienne des orphelins, désactivé par défaut et d’abord en essai à blanc :
reindex mode=prune_orphans(OpenViking ≥ 0.4.21) sur la racine Libris, résultat dans la carte et au journal. Un serveur plus ancien est noté une fois et n’est plus interrogé avant que le réglage soit réenregistré. -
Nextcloud / WebDAV : chaque livre terminé envoyé automatiquement, dossiers manquants créés (#125). Une connexion WebDAV (Mon compte › Connexions Nextcloud / WebDAV) a une nouvelle option, Envoyer automatiquement chaque livre terminé vers cette connexion, avec son dossier et son format : à la fin de la traduction ou de la révision d’un livre dont le compte est propriétaire, le worker l’y envoie comme le ferait Envoyer vers Nextcloud/WebDAV sur la page du livre (même file, mêmes reprises, visible dans Envois précédents ; un livre terminé de nouveau remplace son fichier). Désactivée pour toutes les connexions existantes ; un livre partagé avec le compte ne part jamais tout seul. Un dossier de destination absent est désormais créé avec ses parents (
MKCOL), seulement à l’intérieur de la connexion. Sur téléphone, la liste des connexions n’écrase plus le nom et l’adresse de chaque connexion. La migratione7c1a4b9d352ajoute trois colonnes àwebdav_connections. Google Drive, Dropbox, OneDrive et Mega restent hors périmètre (applications OAuth à enregistrer, pas d’API standard pour Mega) : voir l’issue pour ce qu’ils demanderaient.
Corrigé
-
Paramètres › Licence affiche ses dates à la bonne année. La fin du certificat, la fin de la licence et le dernier contact étaient multipliés deux fois par 1 000 et lus comme des dates situées des dizaines de milliers d’années plus tard.
-
Statistiques : les cartes « Par modèle » et « Échecs par cause » ne sont plus collées (#171). Tous les blocs de la page reprennent l’espacement du reste de l’interface, avec ou sans données, sur ordinateur comme sur téléphone.
-
La table des exports de
docs/architecture.mdne réserve plusepubaux sources EPUB (#173). Toute autre source, ou un intervalle de chapitres, reçoit un EPUB de lecture écrit par Libris ; seule la reconstruction de l’original exige une source EPUB. La table mentionne aussidocx, et un test de la documentation la tient alignée sur la route d’export. -
Les EPUB à mise en page fixe sont refusés à l’import au lieu d’être traduits en un livre inutilisable (#174). La documentation les disait non pris en charge, mais rien ne les détectait : une bande dessinée, un album ou un manuel mis en page était importé, traduit, et son quota de mots consommé. Un EPUB dont le paquet déclare
rendition:layout=pre-paginated(pour tout le livre ou sur chaque page de texte du spine), dont les options Apple Books activentfixed-layout, ou qui porte la méta Kindlefixed-layoutest désormais refusé avec une raison dans la langue de l’interface, dans l’assistant d’import, à l’envoi direct et dans l’API d’automatisation (422 fixed_layout_epub). Quand seules certaines pages de texte sont fixes, le livre est importé avec un avertissement qui dit combien ; une couverture ou une planche fixe sans texte ne change rien. Un volume restauré depuis une archive Libris reste accepté. -
Une mise à jour qui garde un ancien fichier Compose n’est plus silencieuse (#163). Mise à jour par un simple
docker compose pull, une installation faisait tourner les nouvelles images sous l’anciendocker-compose.yml: sans/logs, le journal se désactivait et ne le disait qu’une fois dans la sortie du conteneur. L’API et le worker comparent désormais ce qu’ils montent et écrivent à ce qu’attend le fichier Compose livré dans leur image (/data,/etc/machine-id,/logs, un journal écrit) et en tirent un état,ok,outdatedoudegraded(journal impossible à écrire), avec chaque écart et la commande qui le corrige : relancer l’installateur, ou fusionnerdocker-compose.yml.libris-new. Les administrateurs voient un bandeau et un nouvel onglet Paramètres › Santé de l’installation ;/healthdonne l’état, et son détail à un administrateur ou avecPUBLIC_HEALTH_DETAILS=true;librisctl doctoréchoue sur une configuration dégradée et avertit d’une configuration périmée. -
La cohérence de série ne signale plus la casse comme une contradiction. Les traductions sont désormais comparées comme l’étaient déjà les termes source : « Fil d’araignée » et « fil d’araignée », « RÉINCARNATION » et « réincarnation », apostrophes droites ou typographiques ne font qu’un choix. Chaque choix restant est affiché et appliqué dans l’orthographe la plus utilisée de la série (à égalité, celle du premier tome).
-
Une passerelle Codex restée sur une autre version est désormais signalée (#164). L’API lit la version de la passerelle dans son
/health(qui la donne désormais, derrière le même jeton) et la compare à la sienne ; la réponse est gardée cinq minutes en cache. Un écart apparaît dans les paramètres des providers LLM et sur la connexion Codex, sous la formecodex_bridge: "mismatch"dans/health(les versions elles-mêmes sont réservées aux administrateurs, surGET /api/providers/codex-bridge), et comme un contrôle en échec delibrisctl doctor, avec la commande de mise à jour :COMPOSE_PROFILES=codex docker compose pull && COMPOSE_PROFILES=codex docker compose up -d, ou l’installateur relancé. Une passerelle qui ne répond pas estunknown, jamais une erreur. -
L’alerte de quota n’est donnée qu’une fois par mois quel que soit le fuseau horaire. Le début du mois à partir duquel elle est comptée tombait une heure trop tard sur un serveur réglé sur certains fuseaux (Africa/Casablanca) : une alerte envoyée dans la première heure du mois pouvait l’être une seconde fois. C’est désormais minuit UTC, où que tourne le serveur.
-
CI/tests : plus aucun test ne dépend de l’heure à laquelle il tourne (#167).
scripts/clock_check.shrejoue la suite backend avec l’horloge avancée à minuit UTC, à la fin du mois et de l’année, aux changements d’heure et dans des fuseaux de part et d’autre de la ligne de changement de date ; le jobclock-checkla lance dans un pipeline planifié qui définitLIBRIS_CLOCK_CHECK(à créer à la main, voirdocs/development.md). Les tests de la plage de travail utilisent un jour fixe.
Sécurité
-
Avertissement : les installations Essai et Personnel qui utilisaient l’API d’automatisation, le MCP ou le partage perdent ces fonctions à la mise à jour ; les jetons et liens existants sont conservés et se réactivent avec une licence Studio ou Pro.
-
L’API d’automatisation et le partage suivent la licence (#172). Le serveur de licences signe depuis toujours
automation_apietsharingdans le certificat (Studio et Pro : oui ; Essai et Personnel : non), et Libris les ignorait. Changement visible pour les installations Essai et Personnel : les jetons d’API ne peuvent plus être créés,/api/v1/*etPOST /mcprépondent402 automation_not_licensed(après la vérification du jeton : un jeton absent ou faux reçoit toujours son401) ; aucun nouveau membre ne peut être invité sur un livre et aucun lien de relecture ne peut être créé (402 sharing_not_licensed), et les liens de relecture existants répondent402au lieu d’ouvrir le livre. Rien n’est supprimé : jetons, membres et liens restent listés et révocables, les membres déjà invités gardent leur accès, le propriétaire garde tous ses livres, et tout refonctionne dès que la licence comprend le droit. Les droits se lisent dans le certificat détenu pour cette machine, même expiré (une panne du serveur de licences ne retire aucun droit) ; sans certificat, aucun droit ; un certificat qui ne nomme pas un droit (serveur de licences plus ancien que lui) le garde, comme avant. L’interface masque ce qui n’est pas compris, avec la raison, et Réglages › Licence liste les deux droits.GET /api/settings/licencegagnerights. -
Toute route qui reçoit un identifiant de provider applique désormais la règle de la liste des providers (#178). L’estimation avant import (
GET /api/imports/{id}/estimate) prévoyait tous les providers de l’installation — y compris les providers privés des autres membres et les providers retirés — avec leur nom, leur modèle et leur coût estimé ; elle ne prévoit plus que ceux avec lesquels le compte peut lancer un livre (les siens et ceux partagés par l’installation ; tous, pour un administrateur), jamais un provider retiré, et unprovider_idinaccessible répond le même404qu’un identifiant inconnu. La même faille, qui permettait aussi de dépenser la clé d’un autre membre, est fermée là où l’on choisit un provider : confirmation d’un import (provider_id,escalation_provider_id,fallback_provider_ids→422 Provider inconnu.), réglages par défaut d’une série (POST/PUT /api/series, un provider que la série nomme déjà n’est pas remis en cause), comparaison de providers (POST /api/projects/{id}/jobs,operation: compare) et API d’automatisation (pipeline.provider_id/provider_id→422 unknown_provider, la liste que donnait déjàGET /api/v1/providers).
[0.15.2] - 2026-09-24
Corrigé
-
Un simple
docker compose pullmet désormais à jour la passerelle Codex. Elle est un profil Compose : undocker compose pullouuplancé à la main la laissait sur son ancienne image pendant que l’application avançait. L’installateur écritCOMPOSE_PROFILES=codexdans.env, et une mise à jour l’ajoute à un.envplus ancien ; une valeur choisie par l’administrateur est conservée. -
Présentation e-Soleau. Sans
--with-history,PRESENTATION.mdn’explique plus comment restaurer un historique Git que le dépôt ne contient pas.
[0.15.1] - 2026-09-24
Ajouté
- Les fichiers d’un dépôt e-Soleau pour une version (
scripts/esoleau_bundle.py, job manuelesoleau-bundlesur les tags de version). À partir des seuls objets Git du tag : l’archive des sources, éventuellement l’historique Git en bundle, un manifeste SHA-256 de chaque fichier et une présentation de ce qui fait partie de l’œuvre et de ce qui n’en fait pas partie, prêts à déposer à l’INPI (1 à 100 fichiers, 50 Mo au tarif de base).
Modifié
- Licence et documentation.
LICENSE, le README et le guide de développement décrivent Libris comme le logiciel propriétaire qu’il est, et rien d’autre ; le code de conduite, écrit pour des contributions publiques que Libris ne reçoit pas, est retiré. Le jobesoleau-bundledépose les sources du tag sans leur historique Git.
Corrigé
- Les images transportent leurs licences. L’image de l’application contient désormais
LICENSEetTHIRD_PARTY_NOTICES.mddans/app, et le texte complet de la licence de chaque paquet intégré à l’interface dans/app/frontend/dist/THIRD_PARTY_LICENSES.txt, produit à chaque construction ; l’image du pont Codex les contient dans/service, avec la licence et le fichier NOTICE de Codex et la licence de son environnement Node.js. MIT, ISC, BSD et OFL demandent toutes que leur mention accompagne les copies, et la compilation de l’interface en avait retiré la plupart. La CI vérifie la présence de chaque fichier.
[0.15.0] - 2026-09-24
Ajouté
-
Un journal pour reconstituer un incident depuis un seul endroit (#156). L’API, le worker et les migrations écrivent chacun leurs événements dans un fichier qui leur est propre — en plus de la sortie habituelle des conteneurs — dans un volume
logs, ou dans/opt/libris-production/logssur un hôte déployé parlibris-production-deploy, qui y consigne aussi les étapes de chaque déploiement (deploy.log).librisctl journalles fusionne en une seule chronologie : les derniers événements,-fpour les suivre,export --since 2h --output FICHIERpour une période (--with-containersajoute la sortie de la base et de Codex), filtrés par service, niveau, requête ou travail. Chaque ligne donne l’heure avec son décalage UTC, le niveau, le service, le processus, l’identifiant de requête (X-Request-ID, désormais renvoyé par chaque réponse) et celui du travail ; les traces d’erreur gardent leurs cadres et leur chaîne de causes sur des lignes indentées. Démarrages et arrêts des processus, requêtes de l’API, débuts de travaux (resumed=yes), fins, échecs et migrations passées y figurent. Mots de passe, cookies, jetons, clés de licence, identifiants dans les URL et secrets de la configuration sont masqués — sur la sortie des conteneurs aussi —, les retours à la ligne sont échappés pour qu’aucun faux événement ne puisse être injecté, et les messages susceptibles de citer un livre ou un prompt ne sont jamais recopiés. Les fichiers sont privés (0700/0600), renouvelés àLOG_MAX_MB, conservés surLOG_BACKUPSgénérations etLOG_RETENTION_DAYSjours ; un journal impossible à écrire n’arrête jamais un service et le signale une fois. Voir docs/operations.md#journal et les réglagesLOG_*. -
Chaque image transporte son propre installateur (#145).
/app/deploy/install.shet le modèle de configuration/app/deploy/env.examplevoyagent désormais à côté du fichier Compose. Aprèsdocker pull, un client peut installer ou mettre à jour à partir de la seule image, sans archive ni Git. Quelle que soit la copie lancée (le bootstrap du site ou celle extraite d’une image), elle résoutlatestouLIBRIS_TAGen digest et passe la main à l’installateur de ce digest : installateur, Compose et modèle viennent tous de l’image qui tourne. Une première installation écrit ses secrets0600dans un répertoire de préparation renommé en place d’un seul coup, n’écrase jamais une installation existante et reprend après un démarrage raté ; unLIBRIS_HOMEvide est désormais rempli au lieu de recevoir un sous-répertoire.
Modifié
-
Pont Codex : CLI Codex 0.154.0 → 0.156.1, pour que la liste des modèles d’un compte ChatGPT propose GPT-6 Luna (
gpt-6-luna) et GPT-6 Sol (gpt-6-sol). La liste est toujours lue auprès de l’app-server (model/list) ; entre les deux versions, le protocole ne change que par ajouts. Reconstruire ou tirer l’imagecodex-*pour les obtenir. -
Ruff vérifie aussi les migrations Alembic (#155). Le job CI
backendlançaitruff check app tests: les migrations, exécutées en production à chaque mise à jour, n’étaient jamais vérifiées. Il lance désormaisruff check app tests migrations, et les dix blocs d’import non triés ainsi révélés sont triés (sans changement de comportement). Le guide de développement donne la même commande.
Corrigé
-
Les événements de mémoire sont écrits dans OpenViking en mode vecteurs seuls : plus de régénération des résumés de dossier à chaque écriture, qui multipliait les vecteurs et les appels au modèle (environ 600 vecteurs par événement ; un magasin a atteint 1,9 million d’enregistrements pour 6 000 indexés). Libris ne lit jamais ces résumés. Un serveur qui refuse
processing_modereçoit toujours l’écriture simple, comme avant. -
La traduction d’un volume ne démarre plus avant que son analyse soit complète (#161). Plusieurs chemins laissaient traduire un livre dont l’analyse n’était pas à 100 %, si bien que le glossaire, les personnages et la mémoire du livre n’étaient plus tenus de façon cohérente :
- sous le pilote automatique, un passage dont le provider refusait l’analyse ou répondait sans cesse de travers était sauté, et la traduction démarrait dès que la moitié des passages était analysée ;
- une synthèse de Book Bible abandonnée laissait sa section de côté : en mode strict la section restait « à consolider » pendant que le livre était traduit, et en mode parallèle elle était même comptée comme consolidée, comme les chapitres d’une fusion abandonnée ;
- le pilote automatique validait (figeait) la Book Bible dès 80 % des passages analysés, qu’il manque une section ou non ;
- un travail
translate(bouton ou menu Traduire, action groupée, MCP, API, travail en attente repris après l’ajout de chapitres par une source suivie ou un import, copie pour une deuxième langue faite pendant l’analyse de l’original) vérifiait seulement que la Book Bible n’était pas vide et traduisait des passages sans aucune analyse.
Désormais l’analyse redemande, dans le même travail, tout ce qu’elle avait abandonné et les passages arrivés entre-temps — une fois sur le provider du travail, puis une fois sur chaque provider de secours du pilote (consigné
analysis_catch_up) ; une traduction analyse d’abord les passages qu’elle couvre et qui n’ont pas d’analyse ; la Book Bible n’est validée que si aucune section ne manque, et un rattrapage ne réutilise jamais une synthèse faite pour d’autres chapitres. Ce qui ne peut toujours pas être analysé arrête le travail enblockedavec le nouveaustop_reason = analysis_incompleteet un message qui dit ce qui manque, au lieu de traduire le moindre passage.ANALYSIS_MIN_COVERAGEvaut désormais1par défaut (au lieu de0.5) ; l’abaisser est la façon explicite, pour l’administrateur, d’accepter une traduction avec des trous. La progression montre une traduction qui complète son analyse comme l’étape d’analyse, les statistiques du livre portentanalysis_complete, et la page du livre signale un livre déjà traduit dont l’analyse est incomplète, avec un bouton pour la compléter.
Sécurité
-
Le client d’exemple de l’API ne transmet plus son jeton à un autre serveur par une redirection (dev/Libris_Web#9).
examples/libris_client.pys’appuyait sur la gestion des redirections par défaut d’urllib, qui recopiaitAuthorization: Bearer …vers toute origine désignée par unLocation. Il ne suit désormais une redirection qu’à l’intérieur de l’origine deLIBRIS_URL(même schéma, hôte et port, cinq au plus d’affilée), ne passe jamais dehttpsàhttpet refuse toute autre redirection avec le code d’erreurredirect_refused: ni le jeton ni un livre envoyé n’atteignent une autre destination. Un corps n’est renvoyé que par 307/308 dans cette origine. Testé avec de vrais serveurs locaux pour 301, 302, 303, 307 et 308, d’autres ports et hôtes, des redirections relatives et des chaînes, de Python 3.10 à 3.14. -
Le provider personnel d’un membre ne peut plus faire interroger le réseau interne par le serveur (#157). Avec
members_may_add_providersactif (le réglage par défaut), n’importe quel membre pouvait pointer un provider à lui vers une adresse de bouclage ou du réseau local et faire lire cette adresse par le backend (POST /api/providers/{id}/testrenvoyait ce que le service interne répondait). Un provider ajouté par un membre ne joint désormais que des adresses publiques : un nom qui se résout vers une adresse de bouclage, privée, link-local, partagée (CGNAT), multicast ou réservée — IPv4 ou IPv6, formes IPv4 mappée et NAT64/6to4 comprises — est refusé à l’enregistrement (HTTP 422) et à chaque connexion : test, traductions, nouvelles tentatives, soumission, relève et résultats des lots. Le nom est résolu à chaque requête et la connexion va à l’adresse vérifiée (pas de seconde résolution qu’un DNS rebinding pourrait détourner), le certificat restant vérifié contre le nom ; les redirections ne sont pas suivies et les variables de proxy sont ignorées. Les providers de l’installation, configurés par un administrateur, ne changent pas : un vLLM ou un Ollama du réseau local continue de fonctionner. Mise à jour : le provider d’un membre déjà dirigé vers un modèle local cesse de fonctionner ; un administrateur ajoute ce modèle comme provider de l’installation partagé avec les membres, ou ouvre son adresse aux membres avec la nouvelle variablePROVIDER_MEMBER_PRIVATE_NETWORKS(CIDR, par exemple192.168.1.40/32). Les contrôles d’adresse des webhooks et de WebDAV partagent désormais ce code, et jugent une adresse IPv4 encapsulée en NAT64, 6to4 ou Teredo d’après l’adresse IPv4 qu’elle porte. -
Les preuves de connexion à usage unique ne servent qu’une fois, même à deux requêtes parallèles (#154). Une connexion en attente du second facteur, un code de l’authentificateur, un code de secours, le challenge et le compteur d’une clé de sécurité, un lien de réinitialisation du mot de passe et une demande d’authentification unique étaient lus valides puis marqués consommés plus tard : deux requêtes concurrentes portant la même preuve pouvaient passer toutes les deux (deux sessions pour un seul second facteur, un code ou un lien de réinitialisation utilisé deux fois, deux assertions vérifiées contre le même compteur). Chacune est désormais consommée par une seule instruction que seule une transaction peut gagner (
DELETE … RETURNINGouUPDATEconditionnel), le compte est verrouillé d’abord — l’ordre que suit déjà la révocation — et la requête perdante est refusée. Des tests PostgreSQL font courir deux vraies requêtes sur chaque chemin.
[0.14.1] - 2026-09-23
Modifié
- Les volumes d’une série passent un par un, dans l’ordre de lecture (#153). Une série lancée n’éparpille plus le provider sur tous ses volumes à la fois : le volume 1 démarre en premier, quel que soit l’ordre de lancement, et prend toute la part du provider pour ses passages en parallèle — huit analyses d’un même volume plutôt qu’une sur chacun de huit volumes ; le volume suivant démarre quand il a fini. Les autres livres et séries se partagent toujours le provider comme avant. La file d’attente l’indique pour un volume qui attend son tour.
[0.14.0] - 2026-09-23
Modifié
- Libris a désormais sa propre identité visuelle. L’interface quitte l’indigo par défaut pour une palette d’atelier du livre — papier, encre bleu-noir, bleu de Prusse pour les actions et un seul vermillon, la « rubrique », réservé aux repères — dans les deux thèmes (« Papier » et « Nuit »). Titres, noms de séries et chiffres sont composés en Fraunces, les livres en Source Serif 4, l’interface garde Inter. Un nouveau logo, l’illustration même du propriétaire : un livre ouvert avec un L à empattements sur une page, sa lecture japonaise « エル » sur l’autre et un signet dans la reliure, remplace le logo « A 文 » en image (favicon, barre latérale, connexion, chargement, README), et le signet marque la page active de la barre latérale, la carte de connexion et le passage en cours d’écriture. Les couleurs viennent toujours uniquement des jetons de design et gardent des contrastes WCAG AA.
Corrigé
- Changer de licence ne transfère plus les mots consommés par une autre licence. Les compteurs mensuels sont désormais enregistrés par identifiant de licence signé. Activer la licence B sur une machine qui utilisait auparavant la licence A repart du total propre à B connu du serveur ; revenir à A retrouve le maximum local de A. La migration rattache l’historique des installations existantes au certificat actif au moment de la mise à jour (#146).
[0.13.0] - 2026-09-23
Libris s’ouvre au reste des outils d’une organisation. Cette version connecte les personnes par un annuaire LDAP ou Active Directory, importe des sources depuis un serveur Nextcloud/WebDAV et y envoie les livres terminés, exporte et restaure une série entière en une seule archive, et parle la langue de chacun partout où elle retombait sur le français : courriels, journal des décisions, rapports de l’API, réponses MCP et documentation elle-même.
Ajouté
- Connexion par LDAP / Active Directory. Un administrateur configure un annuaire dans
Paramètres › Authentification unique (préréglages OpenLDAP et Active Directory,
ldaps://par défaut, StartTLS, autorité de certification personnalisée, compte de service, base et filtre de recherche, groupes autorisés et groupe administrateur facultatifs, création facultative des comptes à la première connexion) et le teste avant de l’activer. Le certificat et le nom d’hôte sont toujours vérifiés, les filtres sont échappés, un mot de passe vide est refusé avant toute liaison (sur beaucoup d’annuaires, une liaison anonyme « réussit »), et un utilisateur inconnu, une entrée ambiguë ou un mauvais mot de passe reçoivent la même réponse, décomptée par le même limiteur que la connexion locale. Les comptes sont retrouvés parentryUUID/objectGUID, jamais par nom ni par adresse ; un compte local n’est rattaché que par un administrateur. Le nom, l’adresse et le mot de passe appartiennent à l’annuaire ; la double authentification reste celle de Libris. Guide de mise en place :docs/ldap.fr.md(#132). - Connexions Nextcloud / WebDAV. Chaque compte peut enregistrer ses propres connexions WebDAV
(Mon compte), les parcourir depuis l’assistant d’import (« Depuis Nextcloud/WebDAV ») et envoyer un
livre terminé vers un dossier distant dans n’importe quel format d’export, avec les mêmes états (en
attente, envoyé, échec) et les mêmes reprises que la publication en bibliothèque. Le mot de passe
est chiffré avec
SECRET_KEYet n’est jamais renvoyé. La fonction reste absente tant qu’un administrateur n’a pas listé les hôtes autorisés dansWEBDAV_HOSTS; HTTPS est exigé, sauf sur les réseaux nommés dansWEBDAV_PRIVATE_NETWORKS, la requête part vers l’adresse vérifiée, une redirection vers un autre hôte est refusée et la lecture est bornée parMAX_UPLOAD_MB. Google Drive, Dropbox, OneDrive et Mega ne sont pas encore couverts (#125). - Export et import d’une série complète. Exporter la série écrit un seul ZIP contenant la série (réglages, fiche de style, Series Bible et sa validation, glossaire, identités et fusions, leurs liens vers les entités des volumes, relations) et l’archive de projet de chacun de ses volumes, archivés compris. Sa restauration crée une nouvelle série (« Nom (2) » si le nom est pris), remappe chaque identifiant et vérifie tout avant la moindre écriture ; une archive fautive est refusée en nommant le champ ou le volume en cause. Les providers, les membres, la suspension, le journal d’audit d’origine et les documents OpenViking ne sont délibérément pas transportés (#142).
- Volumes spéciaux. Un volume sans numéro ordinaire — « DX1 », « EX », « LN 14+ », un livre anniversaire — peut porter à la place un repère libre, saisi dans le même champ que le numéro (un nombre entier est un numéro, tout autre texte un repère). Un repère qui commence par un nombre se lit juste après ce volume (« 14+ » après le 14) ; les autres viennent en fin de série. La détection n’invente plus un numéro dont elle n’est pas sûre : « 14+ » n’est plus le volume 14, et un seul nom de fichier atypique ne fait plus perdre leur numéro à tout un lot. La numérotation des chapitres lit aussi correctement « 3-12 » et « Titre 12 - Sous-titre » (#139).
- Les travaux des autres comptes dans la file, grisés. La file d’attente montre désormais, grisés et sans aucun lien, le titre, le propriétaire et l’état des travaux des livres qu’on ne peut pas ouvrir : chacun voit ce qui occupe les providers partagés. Rien d’autre de ces livres ne quitte le serveur : leurs pages répondent toujours 404 (#130).
- Sélectionner d’un coup tous les volumes d’une série depuis la liste des volumes (#143).
- Une courte explication sous chaque réglage du livre et de la série, vérifiée d’après ce que fait réellement le réglage (#127).
- Les contrôles de travaux sont journalisés. Mettre en pause, reprendre, relancer ou annuler un travail — un livre, une série ou une sélection, depuis l’interface, l’API v1 ou MCP — écrit désormais une entrée d’audit qui nomme le compte, le canal et le jeton utilisé (jamais son secret), sans aucun contenu de livre. Une nouvelle carte Journal du compte dans Paramètres › Utilisateurs montre ces entrées aux administrateurs, et le journal de série nomme qui a piloté ses travaux (#117).
Modifié
- Envois jusqu’à 256 Mo.
MAX_UPLOAD_MBvaut désormais 256 par défaut (au lieu de 60) etMAX_UNPACKED_MB1024 (au lieu de 300) ; les envois sans session restent bornés à 1 Mio. Un envoi est toujours lu en mémoire : comptez jusqu’à environ 1,3 Go de RAM pour le plus gros EPUB chargé d’images (#140). - Le lecteur intégré s’ouvre par-dessus le livre au lieu de remplacer toute l’application, et se ferme par Échap, son bouton de fermeture ou un clic à l’extérieur ; une correction non enregistrée demande confirmation avant de fermer (#128).
- Les réglages du livre et de la série s’enregistrent en une fois. Sur un livre, les blocs Livre, Langues, Stratégie, Fiche de style et Pilote automatique partagent un seul Enregistrer les réglages ; sur une série, les paramètres par défaut, le bloc « Quand un modèle échoue » et la fiche de style partagent un seul Enregistrer. Quand une partie est refusée, ce qui a réussi est conservé et la partie refusée est nommée, son brouillon restant à l’écran. Le budget, le partage, les liens de relecture, l’autre langue, le suivi de source, la comparaison de providers et la zone de danger gardent leur propre action. La fiche de style était un formulaire imbriqué dans celui des réglages de la série, ce qui laissait Entrée soumettre le mauvais (#126).
- « Prochaines actions » d’une série regroupe les volumes qui partagent le même reproche en une ligne, avec leur nombre et une action pour toute la série, au lieu d’une ligne par volume (#123).
- Les jetons d’API vivent seulement dans Mon compte. Paramètres › API d’automatisation garde les webhooks de l’installation et renvoie vers Mon compte › Jetons d’API (#122).
- Tout ce qu’une personne lit est dans sa langue. Chaque courriel (invitation, réinitialisation du mot de passe, livraison, alertes, test SMTP), le journal des décisions du pilote automatique et les erreurs stockées, le rapport de fin de l’API v1, les décisions d’import et les webhooks, les descriptions et réponses des outils MCP, ainsi que les commentaires de l’export Word sont désormais écrits dans la langue de la personne qui les lit. Un nouveau test échoue sur toute phrase française du backend sans version anglaise (#133).
- La documentation en français. L’écran Documentation sert la référence de l’API et le journal
des modifications en français quand l’interface est en français.
api,configuration,docker,backup,mcp,autopilot,openviking,codexetldapexistent endocs/*.fr.md;CHANGELOG.fr.mdcouvre les versions 0.8.0 et suivantes. Les documents pour développeurs restent en anglais (#129).
Corrigé
- Une page d’administration ouverte par un non-administrateur dit désormais qu’elle demande un compte administrateur, au lieu d’afficher silencieusement la bibliothèque sous un titre « Paramètres » (#120).
- Les réglages du livre présentent le modèle supérieur avant la chaîne de secours, dans l’ordre où ils sont essayés, comme le faisaient déjà ceux de la série et l’assistant d’import (#121).
- Les cartes de la bibliothèque en grille ne laissent plus un long nom de provider pousser leur contenu hors du cadre (#138).
Notes de mise à niveau
- Trois migrations de base de données (connexions WebDAV, repères de volume, identités LDAP). Sauvegardez la base d’abord, comme pour toute version qui contient des migrations.
- Un
.envqui fixeMAX_UPLOAD_MB=60garde 60 Mo : retirez la ligne ou relevez-la pour profiter du nouveau défaut, et vérifiez qu’un proxy inverse placé devant Libris accepte des corps de cette taille (pour nginx,client_max_body_size 260m). - WebDAV et LDAP sont désactivés par défaut. WebDAV demande
WEBDAV_HOSTS(etWEBDAV_PRIVATE_NETWORKSpour un NAS du réseau local) ; LDAP se configure et s’active dans Paramètres › Authentification unique. Gardez un compte administrateur local quand vous activez LDAP. - Le protocole de licence n’a pas changé depuis la 0.12.0 : aucune mise à jour du serveur de licences n’est nécessaire.
[0.12.0] - 2026-09-22
Ajouté
- Les échecs de modèle comptés par cause, sur toute l’installation. Chaque requête en échec
était déjà classée dans le code au moment où elle se produisait, mais cette catégorie était
ensuite perdue ; le seul endroit où un échec était visible était l’onglet de récupération du
livre concerné.
RequestLogconserve désormaiserror_kind(9 catégories fixes) ; un nouvel endpoint d’administrationGET /api/statistics/failureset un panneau « Échecs par cause » sur l’écran Statistiques affichent le provider, le modèle, la cause, le nombre et la part sur l’ensemble des livres, si bien qu’un problème récurrent avec un provider ou un type de réponse ressort au lieu de rester dispersé livre par livre (#137). - Un interrupteur de pilote automatique pour toute la série. Un seul bouton lance ou met en pause le pilote automatique pour tous les volumes d’une série à la fois. Il remplace « Tout traduire » (Translate everything), un lancement ponctuel, ainsi que la commande distincte de suspension/reprise, qui décrivait un autre mécanisme et ne disait rien du pilote automatique. Une série n’est considérée comme active qu’une fois que l’un de ses volumes a réellement eu un travail (#131).
- Le pilote automatique vérifie la cohérence de la série, pas seulement celle de son livre. Une fois qu’un volume a terminé sa propre boucle de convergence, l’audit de cohérence de la série (glossaire, genres, identités, feuille de style) s’exécute désormais automatiquement si ce volume appartient à une série — sans appel au modèle, par simple comparaison de ce qui est déjà enregistré. L’onglet du pilote automatique du livre affiche un nouveau badge « Cohérence » avec le nombre de divergences trouvées et un lien vers l’onglet de la série ; rien n’est corrigé automatiquement, car chaque divergence exige qu’un humain choisisse laquelle des valeurs contradictoires l’emporte (#134).
Corrigé
- Traductions anglaises manquantes pour les panneaux ajoutés en 0.11. Douze textes livrés
en 0.11 n’avaient pas de version anglaise ; une interface en anglais les affichait en français
sans le signaler. Le garde-fou des traductions (
e2e/translations.spec.ts) refuse désormais les traductions manquantes en plus des collisions, et non plus seulement les collisions (#119). - L’étape active d’un livre est lue sur le serveur, et non devinée. L’interface calculait un état d’avancement complet et distinct chaque fois que l’avancement fourni par le serveur était absent — un chemin qui ne se déclenche jamais en usage normal, mais qui pouvait tout de même contredire silencieusement le serveur pour le même livre. Il est remplacé par une règle simple : la première étape dont les propres chiffres n’indiquent pas qu’elle est terminée (#136).
- Une série se traduit un volume à la fois, dans l’ordre. Lancer une série entière démarrait auparavant tous les volumes ensemble : une panne du provider sur un volume n’empêchait jamais le suivant de démarrer, et plusieurs volumes en cours se partageaient sans aucun bénéfice la capacité du même provider. La traduction d’un volume attend désormais que chaque volume précédent non archivé de la série ait réglé ses passages ; l’analyse peut toujours se chevaucher (#124).
- Une décision d’escalade suit désormais le réglage sur lequel elle a été prise, et pas seulement le travail. Une fois qu’une étape en échec était passée à un modèle supérieur, plus rien ne relisait le réglage « Modèle supérieur » de cette étape avant la fin du travail — si bien que modifier ou effacer un réglage défectueux ne libérait pas l’étape bloquée dessus, et le travail ne pouvait jamais se terminer. Une décision retient désormais aussi le réglage sur lequel elle a été prise et est réévaluée chaque fois que ce réglage a changé depuis (#141).
- Les réglages d’une série s’appliquent désormais à ses volumes existants. Modifier la langue source ou cible, le provider, la qualité, la source de mémoire ou les instructions d’une série ne s’appliquait auparavant qu’aux volumes importés ensuite ; chaque volume existant gardait pour toujours ce qu’il avait, que ce soit décidé ou non. Enregistrer la série propage désormais chaque champ modifié à tous les volumes qui ne l’ont pas défini eux-mêmes. Un volume marque un champ comme le sien dès que quelqu’un le modifie directement sur ce volume, et la série n’écrase plus jamais ce champ à cet endroit. Un champ que la série laisse indéterminé n’écrase jamais un volume qui a une valeur (#135).
- Un vrai bouton contextuel pour une série, « Reprendre » distinct de « Lancer », et une action Annuler séparée. L’interrupteur de série ajouté plus haut dans cette version n’avait encore que deux états (Lancer/Pause) là où une série suspendue en demande trois (Lancer/Pause/Reprendre, sans lever silencieusement la suspension et lancer dans le même clic), plus une action « Annuler » séparée, toujours confirmée, pour les travaux en attente, en pause ou bloqués, et pas seulement en cours (#118).
[0.11.0] - 2026-09-22
Libris accompagne désormais une série entière de la traduction jusqu’à la bibliothèque du lecteur. Cette version ajoute les lots de provider, des commandes durables à l’échelle de la série, les notes du traducteur, un lecteur de correction pleine page et la publication dans un dossier surveillé. Elle fait aussi des comptes locaux et de l’envoi SMTP des parcours d’administration complets, avec confirmation récente de l’identité autour des modifications sensibles des comptes.
Ajouté
-
Publication dans un dossier de bibliothèque surveillé. Mettez un EPUB terminé en file depuis l’écran de son livre, ou automatiquement après la traduction, avec des paramètres de l’installation et des états visibles en attente/publié/échec. Les échecs sont retentés indépendamment de la traduction. Des identifiants stables séparent les homonymes ; une demande de publication plus récente écarte un fichier plus ancien encore en cours d’écriture. Les livres d’origine texte sont aussi convertis en EPUB. Configurez séparément l’analyse/l’import de la bibliothèque externe ; il ne s’agit pas d’une API d’envoi OPDS. Les métadonnées de série EPUB standard portent le nom réel de la série et la position du volume sans renommer les chemins de fichiers stables. L’indexation et la lecture dans Komga et Kavita sont vérifiées ; une mise à jour des métadonnées peut reclasser une série dans la bibliothèque externe, ses marque-pages ne sont donc pas garantis.
-
Notes du traducteur pour les lecteurs. Les termes de glossaire acceptés portent une note distincte destinée au lecteur, placée à la première occurrence, à chaque occurrence ou nulle part. Une opération de modèle dédiée propose des notes sans les appliquer ; les éditeurs examinent chaque proposition. Les exports EPUB utilisent des notes de bas de page liées, les exports texte et Markdown placent les notes en fin de chapitre, et les exports Word les ancrent en commentaires. Les originaux conservés ne reçoivent aucune note. Les échanges de glossaire JSON, CSV et TBX conservent ces réglages.
-
Suspension persistante d’une série entière. Une seule opération serveur met en pause, reprend ou annule ses volumes, avec un rapport par volume. La suspension empêche aussi les démarrages automatiques par surveillance de la source ; la lecture, la correction et l’export restent disponibles. Les reprises excédentaires attendent de façon durable la capacité du compte, du jeton ou du provider. L’interface,
/api/v1/series/{id}/jobs/{action}et l’outil MCPcontrol_seriespartagent les mêmes règles. -
Un lecteur intégré avec correction en ligne. Lisez chapitre par chapitre, affichez au besoin la source, puis modifiez un paragraphe sans perdre la position de lecture. Les corrections passent par l’endpoint existant avec contrôle de révision ; en cas de conflit, le brouillon est conservé. Les membres en lecture seule ne peuvent pas modifier, les originaux conservés sont signalés, et les unités structurées ainsi que la mise en forme protégée restent intactes.
-
Administration des comptes locaux. Les administrateurs peuvent créer des comptes locaux, modifier le nom d’utilisateur, l’adresse e-mail de récupération, le mot de passe, le rôle et l’activité, retirer les facteurs d’authentification locaux, et supprimer un compte avec un transfert explicite de sa bibliothèque. L’identité SSO reste gérée par son fournisseur d’identité. Des garde-fous sur le dernier administrateur et sur le travail en cours empêchent de laisser l’installation inutilisable.
-
Réglages SMTP et inspecteur d’envoi. Configurez la messagerie dans l’interface, testez-la au travers de la vraie file du worker, examinez les messages en attente/envoyés/en échec et relancez les échecs éligibles. Les mots de passe sont en écriture seule ; l’inspecteur ne révèle ni le corps des messages ni les liens de réinitialisation de mot de passe. Les valeurs par défaut issues de l’environnement restent disponibles, et les certificats TLS sont vérifiés.
-
Confirmation récente de l’identité pour les modifications sensibles des comptes. Une preuve valable cinq minutes n’appartient qu’à la session en cours. Utilisez le mot de passe existant et le second facteur requis, une clé WebAuthn enregistrée avec vérification de l’utilisateur, ou une authentification SSO fraîche. Une session SSO silencieuse ne suffit pas à elle seule. La confirmation conserve le brouillon du formulaire et retente une fois la modification refusée ; elle ne prétend pas protéger chaque réglage de provider, de SMTP ou de licence.
-
Propagation de glossaire par MCP.
propagate_termproduit un aperçu par défaut ; l’écriture exige en plus le booléen JSONconfirm: true. L’outil renvoie des décomptes et des exemples, versionne chaque passage modifié et préserve la protection humaine. Aveccontrol_series, le catalogue compte désormais 28 outils. -
Retrait définitif d’un provider. Supprimez les identifiants enregistrés et la disponibilité future tout en conservant l’historique des requêtes. La suppression d’un compte traite explicitement les providers personnels et les connexions Codex ; supprimer une clé d’API enregistrée ne la révoque pas chez le provider externe.
-
Appels par lots vers OpenAI et Anthropic, à moitié prix. Un provider peut être réglé pour envoyer les appels d’un travail sous forme de lot : les deux éditeurs facturent moitié prix ce qui peut attendre, et un livre traduit pendant la nuit est précisément le travail qui le peut. L’intention est consignée avant le POST payant, de sorte qu’un accusé de réception perdu bloque et demande plutôt que de payer deux fois ; un lot soumis attend via
waiting/next_attemptsans être compté comme une panne, et il est récupéré à nouveau après un redémarrage du worker. Les coûts sont enregistrés au prix réduit réellement payé, les budgets réservent le maximum engagé, et un provider qui répond 404 à l’endpoint des lots repasse aux appels synchrones en indiquant que la remise annoncée ne s’applique plus à lui. Vingt-quatre heures, c’est la fenêtre de traitement des éditeurs, jamais une promesse de livraison : un pipeline dont les étapes dépendent les unes des autres demande plusieurs lots successifs, et une annulation ne rembourse pas ce qui a déjà été traité. -
Traduire une série entière en une seule demande. Tout traduire, sur l’écran de la série, exécute tout le pipeline — analyse, traduction, relecture — sur chaque volume. Importer une saga de quarante volumes puis la lancer volume par volume était la façon ordinaire d’utiliser ce produit, et cela n’aurait jamais dû l’être. Chaque volume garde ses propres garde-fous et le rapport les nomme : pas de provider, une licence épuisée, un budget dépassé ou une file pleine refusent ce volume et non ses voisins ; un volume déjà en cours continue au lieu d’être lancé deux fois ; les volumes archivés sont laissés de côté. Une série suspendue refuse le lancement et le dit — rien ne lève une suspension en silence. L’API d’automatisation (
POST /api/v1/series/{id}/jobs/start) et l’outil MCPcontrol_seriesfont de même, et tous deux exigentpipeline:starten plus dejobs:control: un jeton autorisé à arrêter une série ne doit pas pouvoir en facturer une. -
Le modèle supérieur et les replis, décidés une seule fois pour toute une série. Un lecteur qui suit un feuilleton de quarante volumes devait dire quarante fois la même chose : le modèle qui prend en charge une étape en échec et ceux qui prennent le relais en cas de panne existaient sur le volume et sur l’installation, sans rien entre les deux. La série se place désormais entre eux, sous Paramètres de la série › Quand un modèle échoue, et suit la règle que suit déjà la feuille de style : ce que le volume décide l’emporte, ce qu’il laisse ouvert suit la série, et ce que la série laisse ouvert suit l’installation. Un provider cité deux fois n’est essayé qu’une fois : une chaîne qui attend deux fois la fin de la même panne gâche une soirée. Migration de la base de données.
Corrigé
-
Récupération du nettoyage OpenViking après un changement de racine. Les administrateurs voient les décomptes bloqués sur l’ensemble de la file et peuvent retirer un nettoyage en attente sans supprimer les données distantes ni leur piste d’audit. Une analyse quotidienne facultative des orphelins conserve son rapport d’un redémarrage à l’autre et ne met jamais de suppressions en file ; des limites sur les répertoires et les requêtes refusent un inventaire incomplet au lieu de déclarer à tort un état propre.
-
Un passage qui résiste est confié au modèle supérieur avant tout remplaçant, et un livre inachevé ne se dit plus terminé. Deux problèmes différents recevaient la même réponse : un modèle incapable de traiter ce passage — une réponse qui ne s’analyse jamais, un refus, des paragraphes perdus en route — était confié à un remplaçant, ce qui est la réponse à une panne, pas à un modèle qui n’est tout simplement pas assez bon. L’échelle de récupération monte désormais au modèle supérieur (celui du volume, sinon celui de sa série, sinon celui de l’installation) après tout ce que le premier modèle peut être invité à retenter lui-même, et seulement ensuite aux providers de repli ; un provider qui est les deux n’est gravi qu’une fois. Et quand des passages n’ont toujours pas pu être traduits, le badge du pilote automatique affiche « Terminé · 3 passages non traduits » en orange au lieu d’annoncer un succès en vert : un livre auquel il manque un passage n’est pas un livre terminé, et un badge vert est la raison pour laquelle personne ne va le chercher. Le formulaire d’import — chacun de ses parcours — propose désormais le modèle supérieur et la chaîne de repli, puisque c’est là que l’on décide comment un livre sera traduit, des heures avant qu’un échec ne soit découvert.
-
Les réservations d’e-mails survivent aux redémarrages du worker. Des workers concurrents réservent un e-mail en file avant de l’envoyer, renouvellent la réservation pendant un SMTP lent et n’accusent réception que de leur propre tentative. Une nouvelle relance manuelle ne peut pas être acquittée par un ancien expéditeur. Les tentatives épuisées restent visibles ; un plantage après acceptation par le serveur SMTP peut encore provoquer un doublon, si bien que la livraison n’est pas présentée comme « exactement une fois ».
-
Restauration sûre avant un retour à une image antérieure.
librisctl restorevalide l’archive, arrête les processus qui écrivent et effectue un dump de secours avant de recréer uniquement la base de données de l’application. Cela évite les échecs de clés étrangères dus à des tables absentes d’une sauvegarde plus ancienne.--no-startlaisse les processus d’écriture arrêtés afin de pouvoir sélectionner l’image plus ancienne voulue sans réappliquer aussitôt les migrations plus récentes. Un retour arrière qui change le schéma reste une opération de restauration délibérée, et non une rétrogradation destructive automatique. -
Frontières de l’authentification SSO. Les mots de passe locaux et les clés de sécurité ne peuvent pas contourner le fournisseur d’identité externe pour un compte SSO ; la gestion des facteurs locaux n’est pas proposée pour ces identités.
-
Diagnostics de base de données confidentiels. Les erreurs et journaux des travaux ne copient ni les littéraux SQL ni les messages du pilote susceptibles de contenir des extraits du manuscrit. Même une exception au message vide est prise en charge.
-
Réponses de modèle contenant des caractères de contrôle interdits. Les octets NUL n’empoisonnent plus les données de traduction ou d’arbitrage enregistrées. Un refus persistant des données est signalé comme un échec au lieu d’être retenté indéfiniment comme une panne temporaire de la base ; les véritables pannes de connectivité attendent toujours.
-
Limites des entrées et des dépenses MCP. Confirmation et types d’arguments stricts, corps de requête et lots de messages bornés, limitation de débit par message, imputation au budget et à la file du jeton, et refus uniformes pour les objets inaccessibles. L’Unicode invalide est rejeté avant toute écriture par un outil.
-
Permissions entre volumes. Les rapports et la propagation à l’échelle de la série n’incluent que les volumes que l’appelant peut respectivement lire ou modifier ; posséder un volume partagé ne donne aucun contrôle sur l’ensemble de la série.
-
Liens de relecture publics. Les secrets porteurs ne transitent plus dans les chemins de l’API ; les lectures sont limitées en débit et paginées, les réponses interdisent la mise en cache, et le comptage des visites est regroupé. La révocation bloque les requêtes futures mais ne peut pas effacer un texte qu’un lecteur a déjà téléchargé ou copié.
-
Analyses éditoriales bornées. La propagation de glossaire, les rapports de répétitions et l’apprentissage des corrections rejettent les sélections trop volumineuses avant de charger leur texte. Les termes thaïs et laotiens fonctionnent à l’intérieur d’un texte sans espaces. La casse exacte est voulue ; les révisions humaines restent protégées même lorsqu’elles sont explicitement incluses.
-
Des suggestions de qualité honnêtes. Les candidats aux répétitions ne sont pas présentés comme un appauvrissement littéraire avéré. L’apprentissage des corrections utilise les versions du modèle réellement appliquées, et non les réponses rejetées, les originaux conservés ou la révision ultérieure qu’une personne a faite de sa propre formulation.
-
Sûreté et fidélité de l’export Word. Le travail sur les passages sélectionnés, le texte et les différences est borné ; les modifications longues restent des révisions de paragraphe complètes. Les réponses de modèle rejetées n’apparaissent plus comme des brouillons antérieurs. Les caractères XML invalides produisent un refus localisé. Les allers-retours par LibreOffice préservent les modifications suivies et les commentaires ancrés ; les téléchargements de chapitres en Unicode sont vérifiés dans Chromium et Firefox.
-
Plages de travail et comptabilité. Les instants réellement écoulés gèrent les heures répétées ou manquantes des changements d’heure ; les dépenses quotidiennes utilisent la devise comptable de l’installation. La reprise revérifie les garde-fous de licence et de budget, même après une pause manuelle. Le comptage par compte évite les interblocages de clés étrangères de PostgreSQL.
-
Utilisation de la licence en concurrence. Les clés d’installation et les numéros de séquence des rapports sont attribués de façon atomique ; l’utilisation payante des passages et les totaux de l’installation sont rapprochés sans compter deux fois un redémarrage ni perdre de mots pendant un travail concurrent.
-
Engagements de la documentation. Les décomptes MCP suivent le catalogue réellement en service, la configuration de Codex utilise TOML et non le JSON d’opencode, et les conseils sur la confidentialité et les coûts identifient les destinataires externes configurés et les appels déjà admis au lieu de promettre une isolation impossible ou des plafonds de dépenses prépayés. Les liens de paragraphe internes restent sur l’écran de documentation, et les longues tables des matières ne repoussent plus le changelog plusieurs écrans plus bas sur un téléphone.
Notes de mise à niveau
- Sauvegardez la base de données, les fichiers des livres et la configuration/les secrets d’origine
comme une seule installation récupérable. Les migrations de cette version ajoutent le retrait des
providers (
8c4f2a9d6b31) et la suspension des séries (7a1e8b3c5d90), les notes pour le lecteur (9d7c4a2e6f18) et la file de publication (b2e6d1f8a490). La propriété des e-mails ajoutec8e4f1a9d270, puis la confirmation de session ajouted3a7c9e1f650. Les réglages de modèle supérieur et de repli à l’échelle de la série terminent la chaîne àe5b2d8c3f710. Arrêtez l’API et les workers avant la mise à niveau. Les sessions existantes n’obtiennent pas de preuve d’identité fraîche ; une rétrogradation supprime les confirmations SSO en attente mais conserve les demandes de connexion ordinaires. - Avant de poser le tag, comparez
backend/app/licence/server.pyavec la dernière version et vérifiez que le serveur de licences déployé accepte et vérifie les requêtes signées du client. La branchemainde son dépôt ne prouve rien sur ce qui tourne sur le serveur. - Le retour à une image antérieure et la restauration de la base de données sont deux opérations différentes. Un changement de schéma exige la procédure de restauration documentée et une répétition isolée, et non une rétrogradation automatique supposée.
[0.10.0] - 2026-09-21
Libris s’ouvre, et se souvient de ce que vous avez décidé. Cette version porte sur les deux choses qu’une longue traduction perd : les décisions déjà prises, et les personnes qui ne sont pas vous. Un agent de programmation — opencode, Claude Code, Codex — peut désormais piloter toute l’installation par MCP ; une décision de glossaire prise au chapitre 300 rattrape les 299 chapitres qui la précèdent en une seconde et sans frais ; ce que vous corrigez sans cesse vous est proposé en retour comme une règle au lieu de disparaître avec chaque passage ; et les tournures auxquelles un modèle revient encore et encore sont enfin mesurées plutôt que ressenties.
Pour les personnes qui ne sont pas vous : un lien de relecture ouvre un livre à un relecteur qui n’a pas de compte ici et n’occupe aucun siège de votre licence, et un export Word porte vos corrections sous forme de révisions suivies et les doutes du modèle sous forme de commentaires ancrés — le format dans lequel un éditeur travaille réellement.
Avant la mise à niveau : une migration de base de données (
review_links). Rien ne change dans la façon dont quiconque se connecte, aucun réglage n’est requis, et rien de nouveau ne coûte d’argent à lui seul. La plage de travail et le plafond quotidien sont désactivés tant qu’un administrateur ne les active pas.
Ajouté
-
Un serveur Model Context Protocol (
POST /mcp). opencode, Claude Code, Codex — tout ce qui parle ce protocole — peut lire la bibliothèque, préparer un livre, tenir le glossaire et la série, lancer et piloter le travail, et relire la traduction. Vingt-six outils, et chacun d’eux appelle le gestionnaire qu’appelle l’interface web :access()décide toujours quel livre est le vôtre, le garde-fou de licence refuse toujours le travail qui consomme des mots, les budgets mettent toujours en pause un travail qui dépense trop, et le journal d’audit enregistre toujours qui a fait quoi. Un second jeu de règles aurait été celui qui se trompe.L’authentification est celle du jeton d’automatisation, rien de nouveau — même secret
lbr_…, même limite de débit, même compte. Trois portées sont ajoutées afin qu’un agent puisse recevoir le jeton le plus restreint possible pour sa mission :library:read,library:write,library:delete. Un jeton qui lit une bibliothèque ne peut pas la vider, quelle que soit la façon dont on le lui demande, et le refus nomme la permission manquante. Toute suppression exigeconfirm: trueet, sans cela, répond ce qui aurait disparu. Les listes sont paginées et les réponses longues tronquées, avec le total toujours indiqué : une bibliothèque de cinq cents livres n’est pas une réponse, c’est une fenêtre de contexte. Voir docs/mcp.fr.md. -
Une décision de glossaire atteint ce qui est déjà traduit. Décider au chapitre 300 que 金丹 est un Noyau d’Or et non une Pilule Dorée laissait faux les 299 chapitres précédents : le glossaire régit ce qui vient ensuite, jamais ce qui est déjà écrit. Modifier la traduction d’un terme indique désormais quelle part de la série porte encore l’ancien mot, et propose de l’y remplacer. Aucun modèle n’est appelé — cela ne coûte rien et prend une seconde, là où retraduire les volumes serait payé deux fois.
Le mot n’est remplacé que là où il est le mot, et une écriture qui n’espace pas ses mots (chinois, japonais, coréen) est remplacée littéralement. Un passage corrigé à la main est laissé tel quel, compté à part, avec un second bouton pour l’inclure explicitement ; rien n’est écrit avant que le nombre de passages, d’occurrences et de chapitres ne soit affiché, avec une phrase avant et après. Chaque passage garde sa version, si bien que l’ensemble se relit et s’annule comme n’importe quelle autre correction.
-
Ce que vous corrigez sans cesse, proposé en retour comme une règle. Les corrections l’emportent déjà sur tout ce que produit le modèle — mais seulement dans le passage où elles ont été faites, si bien que la même décision était reprise dans le volume 2, puis encore dans le volume 7. Les substitutions récurrentes sont désormais extraites du travail déjà fait et proposées, les plus établies d’abord, avec leur nombre d’occurrences et les passages. Seules comptent les corrections d’un texte produit par la machine : réviser sa propre correction antérieure est un second jet, pas une règle. Rien n’est appliqué — en faire une entrée de glossaire reste la décision d’une personne.
-
Les tics de traduction, mesurés. Le défaut caractéristique de la traduction par modèle de langage est celui que rien ici ne mesurait : passage par passage, le travail semble correct, et lu d’un bout à l’autre, la même main se voit partout. Ce qui est mesuré, ce n’est pas qu’une phrase revienne — un roman se répète volontairement — mais combien de passages source différents une même phrase traduite représente. Quand une seule tournure française couvre trente tournures anglaises différentes, l’auteur a écrit trente choses et la traduction n’en dit qu’une. Trois familles : l’aplatissement (commencez par là), les tournures fréquentes (refrain ou béquille, une personne tranche), et la richesse du vocabulaire, lue par rapport à la moyenne propre au livre. Aucun modèle n’est appelé, et
series=truelit tous les volumes à la fois, là où une habitude se voit le mieux. -
Un lien de relecture, pour quelqu’un qui n’a ni compte ni siège. Ce que vend une licence, ce sont des comptes sur une installation ; montrer une traduction à un relecteur ou à un éditeur en coûtait donc un — ou obligeait à s’envoyer des fichiers dans les deux sens, ce qui est le meilleur moyen de perdre une correction. Un lien ouvre un seul livre, en lecture seule, expire, et se révoque en un clic. Suivre un lien ne crée aucun compte, n’ouvre aucune session et ne dépose aucun cookie ; seule l’empreinte du secret est conservée, si bien que l’adresse n’est affichée qu’une fois et ne peut pas être relue. L’original ne voyage pas, sauf si le lien a été créé pour le transporter. Toutes les raisons pour lesquelles un lien échoue donnent la même réponse 404 : celui qui détient une adresse n’apprend rien sur le fait qu’elle ait jamais signifié quelque chose.
-
Un export Word, avec les corrections en modifications suivies et les doutes en commentaires. Le DOCX était accepté à l’import et n’existait pas à l’export, ce qui laissait hors de portée le seul format dans lequel travaille un éditeur professionnel. Ce que le modèle a écrit et ce qu’une personne a laissé sont comparés mot à mot et deviennent de vraies révisions, qu’un éditeur accepte ou rejette comme il le ferait pour le travail de n’importe quel traducteur ; un original conservé, un doute soulevé par le modèle, une note de relecture encore ouverte ou un score faible devient un commentaire ancré sur le passage plutôt qu’un rapport que personne n’ouvre. Décochez les révisions pour remettre un document propre — ce qu’on envoie à un client plutôt qu’à un éditeur.
-
Une plage de travail, et un plafond pour la journée. Une file équitable sait ordonner le travail ; elle ne savait pas attendre. Les modèles sont moins chers et moins sollicités la nuit, et un budget de livre arrête un livre alors que rien n’empêchait une installation de dépenser en un après-midi l’équivalent d’un mois. Les deux se trouvent dans Paramètres › Budgets et sont désactivés par défaut. Aucun des deux n’interrompt quoi que ce soit brutalement : hors de la plage, ou au-delà du plafond, un travail en cours est différé, pas annulé — il retourne en attente avec la prochaine ouverture comme prochaine tentative, si bien qu’il repart de lui-même sans rien à cliquer, et son message indique quand. Une plage qui passe minuit est le cas ordinaire.
Corrigé
-
Un malentendu n’est plus lu comme une révocation. Le renouvellement d’un certificat l’effaçait sur n’importe quelle réponse 4xx du serveur de licences. Un 422 signifie « je n’ai pas compris votre requête » — il ne dit rien de la licence — et il coûtait à une installation les trois jours de grâce qui existent précisément pour qu’un problème du serveur de licences n’interrompe jamais un lecteur. C’est ce qui a arrêté la production le 2026-09-21 : la 0.9 a commencé à envoyer un champ que le serveur déployé ne connaissait pas, et Libris a lu le refus comme une révocation alors que la licence était valide depuis le début. Quatre codes retirent désormais le certificat, et ce sont les quatre qui signifient que la licence n’est plus valide ; tout le reste est traité comme la panne qu’il représente.
-
Un message impossible à envoyer n’arrête plus tous les e-mails derrière lui. Un titre de livre contenant un saut de ligne — saisi, ou lu dans le
dc:titled’un EPUB importé — ne peut pas être écrit dans un en-tête d’e-mail. Ce refus est correct ; il se produisait dans la boucle de la boîte d’envoi, après la mise en file du message, et personne ne l’interceptait : l’expéditeur mourait, l’annulation de la transaction faisait que le nombre de tentatives n’avançait jamais, et le même message se retrouvait en tête de file après chaque redémarrage. Tout ce qui se trouvait derrière s’arrêtait définitivement — un livre terminé, un quota qui s’épuise, une licence impossible à renouveler, et la réinitialisation d’un mot de passe. Le saut de ligne est désormais supprimé là où l’en-tête est construit, et tout ce qui ne peut pas être envoyé est mis de côté et nommé au lieu de bloquer le passage. -
Exporter un chapitre dont le titre n’est pas en latin-1 ne répond plus 500. Un en-tête transite en latin-1, et le nom de fichier y était écrit brut : un chapitre intitulé 第一章 ou Глава 1 — le cas ordinaire pour ce produit — provoquait une erreur d’encodage à la sortie. Il utilise désormais la forme encodée que l’API d’automatisation a toujours utilisée, et le nom est conservé au lieu d’être abandonné.
-
Une licence qui change de machine conserve les sièges qu’elle déclare. La branche qui déplace une licence vers une nouvelle machine créait l’activation sans le nombre de comptes que l’instance venait d’envoyer, si bien que le back-office affichait un nombre inconnu et que l’anomalie de sièges n’était pas enregistrée avant le battement de cœur suivant.
[0.9.0] - 2026-09-21
Un Libris que plusieurs personnes se partagent. Une licence vend à une installation un nombre de mots par mois ; cette version dit comment les personnes qui l’utilisent se le partagent, et qui elles sont. Un administrateur attribue à chaque compte sa part du mois et administre les providers de l’équipe ; chaque compte configure ses propres providers avec sa propre clé ; une installation déclare la devise dans laquelle elle compte, et une grille tarifaire exprimée dans une autre devise est convertie au moment où on la saisit. La connexion gagne tout ce qu’un compte peut vouloir en plus d’un mot de passe : un code d’une application d’authentification, une clé de sécurité, ou l’authentification unique de l’organisation, chacun avec les dix codes de récupération qui rendent la perte d’un téléphone surmontable.
Pour les lecteurs, un webnovel devient un livre — Libris écrit lui-même l’EPUB d’un volume qui n’en a jamais eu — et on peut lui demander une plage de chapitres, désignés par les titres des chapitres qu’il contient. La référence de l’API et ce journal des modifications se lisent dans Libris, si bien qu’un client lit la documentation de la version qu’il utilise. Et un incident de production est corrigé à la racine : un pool de connexions dimensionné pour les providers, et une panne qui cesse de se présenter comme une base de données qui n’a jamais été indisponible.
Avant de mettre à jour : six migrations de base de données, et le fichier Compose fourni règle désormais
max_connections=200sur PostgreSQL. Recréez les conteneurs (librisctl up) plutôt que de les redémarrer — un redémarrage conserve la base créée par l’ancien fichier. Rien ne change dans la façon dont quiconque se connecte tant qu’un compte n’active pas une deuxième étape ou qu’un administrateur ne configure pas un provider.
Corrigé
-
L’observabilité ne ressemble plus à un travail mort. Une analyse passe de longs moments à écrire dans la base de données sans une seule requête à un modèle :
consolidationparcourt les passages pour reconstruire la chronologie,memoryécrit des analyses déjà calculées. Pendant une heure d’affilée, le panneau affichait 0 requête en cours et un tableau dont la dernière ligne datait d’une heure — ce qui donne l’impression d’une panne, alors que le livre avançait normalement. Le panneau nomme désormais l’étape en cours et dit, en toutes lettres, qu’elle ne fait aucun appel au modèle et qu’aucune requête n’est attendue tant qu’elle dure.Dans la même carte, « 1 h 40 restantes · confiance élevée » était calculé à partir du débit de requêtes pendant une étape qui n’en fait aucune : l’estimation mesurait quelque chose qui n’avait pas lieu. Elle répond désormais
silentpour ces étapes, et l’interface affiche un tiret plutôt qu’un chiffre qu’elle ne peut pas garantir. Ce qui a déjà été dépensé est un fait, pas une extrapolation, et reste affiché.Et chaque mesure renvoyée par l’endpoint porte désormais un nom :
input_tokens,cache_hits,duration,costetactiveétaient affichés tels qu’ils sont écrits dans la base, à côté de mesures libellées. Les secondes s’écrivent comme une durée et l’argent comme de l’argent. -
Deux panneaux ne peuvent plus être en désaccord sur le même mot. Les traductions de l’interface forment une seule table indexée par le texte français, si bien qu’une clé générique enregistrée à deux endroits —
Activer,Faible— prenait le sens que lui donnait l’ordre des imports, et l’anglais affiché changeait d’une compilation à l’autre. Un test refuse désormais toute nouvelle clé française enregistrée avec deux valeurs anglaises différentes, et liste celles qui existent déjà pour que la liste ne puisse que raccourcir. -
Un pool de connexions dimensionné pour les providers, et une panne qui dit son vrai nom. Une installation de production a journalisé 113
database_unavailableen cinq heures alors que PostgreSQL était en parfaite santé — journaux propres, points de contrôle réguliers, pas un seul verrou en attente. Le moteur n’avait jamais reçu de taille de pool ; il utilisait donc la valeur par défaut de SQLAlchemy, 5 connexions plus 10 en pointe ; un provider d’une capacité de 16 pouvait à lui seul l’épuiser, et chaque appelant attendait alors cinq secondes avant de recevoir uneTimeoutError, soit la même classe d’exception qu’une base de données hors service. Rien n’a été perdu — le délai de grâce des baux a remis chaque travail en file — mais la matinée est passée à lire les journaux d’une base de données qui n’avait aucun problème.Le pool est désormais un réglage (
DB_POOL_SIZE,DB_POOL_MAX_OVERFLOW,DB_POOL_TIMEOUT), car la demande change sans redéploiement : un administrateur augmente les Livres simultanés d’un provider depuis l’interface. Sa valeur par défaut couvre, avec de la marge, la somme des capacités des providers — et non la plus grande d’entre elles, puisque des livres qui tournent sur des providers différents s’additionnent — plus les boucles qui ne s’arrêtent jamais. Les deux processus indiquent désormais au démarrage s’il les couvre :db_pool=ok capacity=… providers=…, oudb_pool=undersizeden nommant ce qu’il faut augmenter, pour que la prochaine personne qui reconfigure un provider lise une ligne au lieu de refaire le diagnostic. Le PostgreSQL fourni reçoitmax_connections=200dans la foulée : agrandir un pool sans agrandir ce qu’il y a derrière ne fait que déplacer la panne. Et un pool épuisé est journalisé commepool_exhaustedplutôt que comme une base de données qui n’a jamais été indisponible. -
Changer l’adresse d’un compte n’échoue plus sur un champ que le serveur a lui-même écrit. Mon compte › Notifications renvoie ce qu’il contient et ce dont l’installation est capable — si un serveur de courrier est configuré, si un dossier de dépôt existe — et le formulaire renvoyait cet objet entier, comme le fait un formulaire. L’endpoint le refusait à cause de ces deux champs en lecture seule, avec une erreur 422 sur laquelle personne ne pouvait agir :
configured: Extra inputs are not permitted. Il les lit et les ignore désormais, et l’interface n’envoie que ce qu’elle a le droit de modifier.
Modifié
-
L’onglet Observabilité dit toujours quelle étape, et où elle en est. Le compteur figurait dans l’en-tête du livre et nulle part ailleurs ; le panneau qui existe pour répondre à « où en est-on ? » ne nommait une étape que lorsque celle-ci ne faisait par hasard aucun appel au modèle. Il affiche désormais, pour chaque travail en cours : l’étape, sa progression (
421 of 1071), et — lorsque l’ordre des étapes est connu d’avance, ce qui est le cas pour une analyse — son rang parmi combien (step 4 of 5). Une Book Bible construite en arbre ajoute son niveau, le pilote automatique ajoute sa phase, et un livre sur lequel rien ne tourne le dit plutôt que d’afficher une carte vide.Une traduction n’annonce délibérément aucune position : sa propre séquence dépend de ce que son lancement a demandé — une passe de rattrapage, une passe de cohérence, une relecture finale —, si bien qu’annoncer « étape 2 sur 5 » dans une séquence qui peut en compter trois ou six serait un chiffre de plus qui ne tient pas.
-
Des compteurs qui disaient deux fois la même chose, et un statut qui nomme son étape. Une carte de série affichait
100 % traduit · 0/986 validésà côté d’une pastille indiquantEn cours: trois chiffres qui se contredisaient, parce que le deuxième comptait les validations humaines — une mesure de la lecture, pas de l’avancement, légitimement nulle pour un livre traduit par le pilote automatique. La carte indique désormais combien il y a de passages, quelle part est traduite, puis ce qui bloque : passages en échec, passages à relire, ou prêt à exporter quand il n’y a rien. La pastille nomme l’étape réellement en cours — Analyse en cours, Traduction en cours, Relecture en cours — plutôt qu’un En cours générique. -
Les langues se choisissent dans une liste, par nom et par code, dans les réglages du livre, les valeurs par défaut de la série et l’assistant d’import ; un champ reste disponible pour un code dont Libris ne connaît pas le nom. La valeur enregistrée reste un code, donc rien ne change pour les livres déjà présents dans la bibliothèque.
-
La Bible de série se lit par blocs plutôt que comme un mur de texte. Univers, lieux, conventions, chronologie et personnages occupent chacun leur propre cadre, les lignes d’une liste se distinguent les unes des autres, et une fiche de personnage est en retrait à l’intérieur de sa section.
-
Une licence vend des comptes, pas des machines. Une licence correspond à une installation ; ce qu’elle autorise, c’est le nombre de personnes qui peuvent s’y connecter. Libris indique désormais combien de comptes actifs il porte et refuse la création d’un compte au-delà de ce que la licence autorise — et seulement cela : la connexion, le travail, la lecture et l’export ne sont jamais touchés, car une licence qui se réduit ne doit enfermer personne hors de l’installation sur laquelle il travaille. Réactiver un compte reprend une place et suit la même règle ; en désactiver un est toujours permis. Réglages › Comptes indique combien de places sont occupées sur combien. Les machines sont toujours comptées et affichées, avec un plafond large.
-
Les mots du mois parviennent au serveur de licences à la fin d’un travail, et plus seulement au prochain battement de cœur six heures plus tard : un appel par travail, jamais par passage, et un serveur injoignable ne coûte rien puisque le battement de cœur suivant transporte le même chiffre.
Ajouté
-
Authentification unique (OpenID Connect), pour les installations qui appartiennent à une équipe. Une entreprise dispose déjà d’un endroit où les personnes sont créées et supprimées ; l’interroger, plutôt que de tenir une seconde liste de mots de passe à côté, est ce qui fait qu’un départ ferme réellement la porte. Un administrateur fournit un émetteur (issuer), un identifiant client et un secret (Réglages › Authentification unique) et Libris fait le reste : il découvre le provider au lieu qu’on le lui décrive, y envoie les personnes avec un
state, unnonceet un défi PKCE, et vérifie le jeton d’identité qu’il reçoit en retour — signature contrôlée avec les propres clés du provider, émetteur, audience, expiration, et le nonce qui lie le jeton à la requête. Une connexion à laquelle il manque l’un de ces éléments est refusée, en disant lequel.Un compte est retrouvé par le nom que lui donne le provider (
sub), jamais par une adresse que celui-ci se trouve envoyer : une adresse change de mains, et s’appuyer sur elle livrerait un compte à quiconque hérite d’une boîte aux lettres. Une personne inconnue est refusée tant qu’un administrateur n’a pas créé son compte, sauf si l’installation demande que les comptes soient créés à la première connexion — auquel cas chaque nouvelle personne occupe une place de la licence, premier arrivé, premier servi, et est refusée comme n’importe quelle autre une fois les places épuisées.Deux conséquences en découlent, et Libris les dit plutôt que de laisser les gens les découvrir. Un compte ouvert par un provider n’a pas de mot de passe Libris : Mot de passe oublié le lui dit au lieu de promettre un courriel qui n’arrivera jamais, et aucun mot de passe ne permet de s’y connecter. Et la deuxième étape relève du provider : une organisation qui exige une clé ou un code à sa propre porte l’a déjà obtenu, donc Libris ne le redemande pas. La vérification est celle de
pyjwt— la confusion d’algorithmes et la sélection de clé sont exactement là où une vérification écrite à la main se trompe. Migration de base de données. -
Des clés de sécurité, pour les comptes qui en veulent une. Un code d’application d’authentification protège d’un regard par-dessus l’épaule et d’une fuite ; il ne protège pas de la troisième menace — une page qui ressemble en tout point à Libris et demande le code comme le ferait Libris. Une clé de sécurité en protège, et par construction : elle signe un défi tiré par ce serveur, pour ce domaine, et une page d’un autre domaine ne peut pas lui demander une signature que Libris accepterait. Mon compte › Double authentification en enregistre une, lui donne un nom et affiche sa dernière utilisation ; un navigateur qui n’en est pas capable — pas de HTTPS, un navigateur trop ancien — en est informé, plutôt que de se voir proposer un bouton qui ne peut pas fonctionner.
Une clé est un moyen de plus de franchir la deuxième étape, à côté du code de l’application d’authentification et des dix codes de récupération, pas un remplacement du mot de passe. Un compte peut détenir une clé, une application d’authentification, ou les deux ; détenir l’une ou l’autre est ce qui active la deuxième étape, et la première enregistrée apporte avec elle les codes de récupération. Retirer la dernière clé d’un compte qui n’a pas d’application d’authentification met fin à la deuxième étape, et aux codes avec elle.
Deux règles sont énoncées clairement plutôt que fondues dans un « invalide » : une clé dont le compteur de signatures n’avance pas est une copie de clé, et elle est désignée comme telle ; et une clé est liée à un seul domaine (
WEBAUTHN_RP_ID, à défaut l’hôte de la première origine autorisée), si bien qu’une installation joignable à deux adresses enregistre ses clés sous l’une d’elles. La vérification est celle de la bibliothèquewebauthn— la seule chose de ce produit qui ne doit pas être écrite à la main. Migration de base de données. -
La référence et le journal des modifications, lus dans Libris. « Où l’API est-elle documentée ? » n’avait qu’une réponse — un fichier dans un dépôt auquel un client n’a pas accès — et « qu’est-ce qui a changé dans cette version ? » n’en avait aucune. Les deux documents voyagent désormais dans l’image et se lisent depuis l’application (Documentation, dans la navigation, pour tous les comptes) : la référence que l’on lit est celle de la version que l’on utilise, pas celle de ce qui se trouve sur un site web aujourd’hui. L’onglet API contient toute la référence avec ses exemples et ses tableaux, accompagnée d’une table des matières ; l’onglet Nouveautés contient ce journal des modifications. Le schéma OpenAPI est toujours là pour les outils qui en ont besoin, à un lien de distance.
Le Markdown est dessiné sous forme d’éléments, jamais sous forme de HTML : injecter du HTML dans la page reviendrait à faire confiance à un document pour ne contenir aucun script, pour toujours, dans toutes les versions. Un petit moteur de rendu écrit pour l’occasion lit ce qu’utilise la documentation — titres, paragraphes, blocs de code, listes, tableaux, citations, ainsi que code en ligne, gras, italique et liens — et affiche tout le reste tel quel, comme du texte.
-
Une deuxième étape à la connexion, pour qui la souhaite. Le mot de passe est ce qu’utilisent la plupart des intrusions : lu par-dessus une épaule, récupéré dans la fuite d’un autre site, ou saisi dans une page qui ne fait que ressembler à Libris. Un compte peut désormais exiger en plus un code à six chiffres fourni par une application d’authentification (Mon compte › Double authentification) : un QR code à scanner, le code ressaisi pour prouver que l’application fonctionne — une deuxième étape que personne ne peut franchir, c’est une porte verrouillée avec la clé à l’intérieur — et c’est seulement ensuite qu’elle entre en vigueur. La connexion se fait alors en deux temps : le mot de passe donne une demi-connexion, qui n’ouvre rien et dure cinq minutes, et le code la termine. Un code est refusé pendant le reste de ses trente secondes de validité, si bien qu’un code lu par-dessus une épaule ne sert à rien à qui l’a lu.
Dix codes de récupération l’accompagnent, affichés une seule fois et conservés sous forme hachée, chacun valable pour une seule connexion : un téléphone se perd, tombe, se remplace, et une mesure de sécurité capable d’empêcher quelqu’un d’accéder aux livres qu’il traduit depuis des mois est une mesure que personne n’active. Ils peuvent être renouvelés à tout moment, ce qui retire les anciens.
Un administrateur peut la retirer d’un compte, jamais l’y ajouter (Réglages › Utilisateurs) : un collègue bloqué dehors est un problème qu’une installation doit pouvoir résoudre, alors que choisir l’application d’authentification de quelqu’un d’autre n’est pas du ressort d’un administrateur. Chaque retrait est inscrit dans le journal d’audit avec son auteur, et met fin aux sessions de ce compte. L’API d’automatisation n’est pas touchée — un jeton est un secret à part entière, et faire porter un code à un appel automatisé reviendrait à conserver le secret juste à côté. TOTP est implémenté d’après la RFC 6238 dans le code plutôt que tiré d’une bibliothèque ; le QR code est dessiné par
segno. Migration de base de données. -
Un webnovel devient un livre, avec seulement les chapitres demandés. Un feuilleton vit dans Libris sous la forme d’un volume texte : des chapitres TXT ou JSON, sans EPUB derrière. Son lecteur pouvait emporter un ZIP de fichiers texte ou un long fichier consolidé, et ni l’un ni l’autre ne s’ouvre dans une liseuse — l’export EPUB était purement et simplement refusé pour ces volumes. Libris écrit désormais le livre lui-même : une page par chapitre, un document de navigation, la langue et l’auteur du volume, le tout validé par EPUBCheck comme tout EPUB qu’il produit. Et on peut lui demander une plage de chapitres — Options d’export › Du chapitre / Au chapitre, l’option qui limitait déjà les formats texte —, si bien que quelqu’un qui a suivi un feuilleton jusqu’au chapitre 520 peut prendre les cinquante derniers et rien d’autre. Le fichier porte le nom des chapitres qu’il contient (Le Rejeton 471-520.epub), car plusieurs tranches d’un même livre finissent sur la même étagère. Un volume EPUB pour lequel on demande une plage reçoit la même copie de lecture, et la boîte de dialogue le dit : le texte, sans les images ni la mise en forme de l’original.
-
Chaque montant dit désormais ce qu’il est. Les prix des providers se saisissent à la main, par million de jetons, et rien ne disait en quelle monnaie : l’interface affichait des nombres nus sous une note indiquant « dans la devise où ils ont été saisis ». Une installation déclare désormais une devise comptable (Réglages › Budgets) : tous les prix sont exprimés dans cette devise, tous les coûts calculés à partir de ces prix aussi, et chaque montant affiché par l’interface — estimations, budgets, statistiques, comparaisons de providers — porte son symbole. Une seule devise, et non une par provider, à dessein : un total qui additionne des dollars et des euros n’est pas un total. La changer déclare ce que représentent les nombres enregistrés ; cela ne les réécrit jamais.
En plus de cela, la conversion se fait là où l’on saisit : une grille tarifaire en dollars peut être saisie en dollars dans une installation qui compte en euros, convertie une seule fois, à l’enregistrement, aux taux de référence quotidiens de la Banque centrale européenne — publics, gratuits, sans compte —, récupérés une fois par jour par le worker et conservés avec la date qu’ils portent. Une installation sans accès sortant propose simplement sa propre devise, et rien d’autre ne change.
-
Une installation partagée par plusieurs personnes, administrée comme un tout. Une licence vend à une installation un nombre de mots par mois ; jusqu’ici, la série en trois volumes d’une seule personne pouvait l’épuiser entièrement sans que personne s’en aperçoive avant que le mois ne s’arrête. Un administrateur peut désormais attribuer à chaque compte une part du mois — Réglages › File d’attente, à côté des quotas qui existaient déjà ; vide, elle vaut la valeur de l’installation, et
0signifie aucune limite propre. Les mots sont ceux que compte la licence : mots source, une fois par passage, imputés au compte propriétaire du livre, quelle que soit la personne qui a appuyé sur le bouton. Ce qui est refusé est ce que la licence refuse — un lancement et un appel au modèle, jamais la lecture, l’export, la correction ou la suppression —, et le livre en cours est terminé dans le même dépassement plutôt que laissé à moitié. Chacun voit ce qui reste de son propre mois sur la page de la file d’attente ; un administrateur voit, compte par compte, à quoi le mois de l’installation a été consacré. Migration de base de données. -
Des providers qui appartiennent à quelqu’un. Ils appartenaient tous à l’installation, configurés par un administrateur et proposés à tout le monde. Il existe désormais deux dispositions, côte à côte. Un administrateur configure ceux de l’installation et peut en garder un non partagé — le modèle coûteux reste hors de portée des autres. Et chaque compte configure les siens, avec sa propre clé (Mon compte › Mes providers) : le provider d’un membre lui appartient, et aucun autre compte ne le voit, ne l’utilise ni ne pourrait y rattacher un livre. Une installation qui préfère détenir toutes les clés ferme la seconde disposition (Réglages › Providers LLM), et seuls les administrateurs configurent quoi que ce soit à partir de là — ce qu’un membre a déjà mis en place reste utilisable, il ne peut simplement plus le modifier. Ce qui existait auparavant est inchangé : chaque provider existant appartient à l’installation et reste partagé. Migration de base de données.
-
Un moyen de revenir dans un compte, un visage pour l’incarner, et un moyen d’en sortir. Mot de passe oublié ? envoie un lien valable une heure et à usage unique à l’adresse du compte, et répond exactement la même chose que le compte existe ou non — une réponse différente permettrait de dresser la liste des comptes d’une installation. L’utiliser ferme toutes les sessions de ce compte, car un mot de passe oublié a peut-être aussi été vu ; seule l’empreinte du jeton est conservée, comme pour une session ou un jeton d’API. Un compte peut porter une photo (PNG, JPEG ou WebP, 512 Ko, reconnue à ses premiers octets plutôt qu’à ce que prétend l’envoi) et peut être supprimé — avec ses jetons et ses sessions, ses livres confiés d’abord à quelqu’un d’autre, le mot de passe redemandé, et jamais le dernier administrateur actif. Un jeton d’API, enfin, peut être supprimé et pas seulement révoqué : révoqué d’abord, toujours, car un jeton qui disparaît de l’écran alors qu’il fonctionne encore est une clé que personne ne peut plus désactiver. Migration de base de données.
-
Un volume peut suivre le flux sur lequel ses chapitres sont publiés. Un webnovel paraît un chapitre à la fois, pendant des mois. Libris savait traduire un nouveau chapitre dès qu’on le lui donnait — quelqu’un devait encore remarquer qu’il existait, le copier et l’envoyer, et c’est cette attente qui constituait le travail. Suivre une source associe une adresse de flux à un volume texte : Libris le consulte toutes les quelques heures, dans l’ordre de lecture (un flux publie le plus récent en premier, un livre se lit dans l’autre sens), importe ce qui est nouveau et fait passer son texte par le même chemin que n’importe quel chapitre TXT, et — si on le lui demande — lance la traduction. Trois règles l’encadrent : un flux, jamais une page, car un flux est une interface publiée faite pour être interrogée régulièrement, ce que n’est pas le moissonnage d’un site ; une liste d’autorisation (
SOURCE_WATCH_HOSTS), avec le même refus des adresses privées que pour un webhook sortant ; et ce qui est importé est ce que donne le flux — une entrée qui ne contient qu’un lien est mémorisée comme vue et signalée au lecteur, jamais récupérée dans son dos. Un flux en échec est signalé à côté du réglage, et la surveillance continue. Migration de base de données. -
Comparer des providers, depuis l’interface. Libris traduit avec le modèle que choisit son lecteur, et c’est un choix que personne ne peut faire à sa place : un modèle vingt fois moins cher peut suffire pour un light novel et être sans espoir sur un livre à trois registres et cent noms propres. Le seul moyen de le savoir était de traduire un livre entier et de le lire. Comparer des providers en prend deux à quatre, une poignée de passages répartis sur les chapitres narratifs, et envoie chaque passage à chaque provider avec le même prompt et le même contexte, le cache des réponses désactivé. Le rapport donne, par provider : les passages traduits et en échec avec la raison, le temps moyen, le coût réel aux prix enregistrés avec chaque appel, le coût pour mille mots, ce qu’ont trouvé les vérifications automatiques, et le score de qualité que Libris aurait attribué à ces passages, calculé par la même fonction que celle du tableau de bord. Adopter pour ce livre bascule le livre sur le provider choisi. Rien n’est écrit dans le livre — les traductions restent dans le rapport, côte à côte avec le texte source — et les appels sont réels, payants, enregistrés sous leur propre opération et décomptés de la licence comme n’importe quel autre appel au modèle. La comparaison qui existait sous forme de script de maintenance est désormais un travail comme les autres : file d’attente, licence, budget, et un rapport conservé avec lui.
-
Le livre terminé, là où le lecteur lit vraiment. Libris traduit sur un serveur et les gens lisent sur un appareil ; entre les deux, il y avait un navigateur, un téléchargement et un câble, pour un livre demandé des heures plus tôt et qu’on avait cessé de surveiller. Un livre terminé part désormais, si son lecteur l’a demandé, vers une adresse de son choix — Mon compte › Notifications, une adresse distincte de celle des notifications, car une adresse Kindle n’est pas une boîte aux lettres que quelqu’un lit — et dans un dossier choisi par l’installation (
DELIVERY_DIR), où Calibre-Web, KOReader ou un client de synchronisation peut le récupérer. Aucun des deux n’est activé par défaut, et renseigner l’adresse est le seul consentement qui existe. Le fichier est construit au moment où le message part plutôt qu’au moment où il est mis en file, si bien que la boîte d’envoi reste légère et qu’un message qui a attendu une heure transporte le livre tel qu’il est à cette heure-là ; un livre au-delà deDELIVERY_MAX_MBest annoncé avec son adresse au lieu d’être joint, car un serveur de courrier qui refuse la pièce jointe ne délivre rien du tout. Un livre qui n’est pas un EPUB, ou qui n’est pas terminé, n’est pas livré, et rien n’échoue pour autant. Migration de base de données. -
Une terminologie reprise d’une traduction que quelqu’un a déjà faite. Un lecteur qui reprend une série là où son éditeur s’est arrêté possède déjà trois volumes dans sa langue, et aucun moyen de dire à Libris comment s’y appelle le Tide Keeper : il devrait saisir le glossaire à la main, terme par terme, et manquerait précisément ceux auxquels il n’a jamais pensé. Reprendre une traduction existante, dans l’onglet du glossaire, prend un TMX — déjà aligné, c’est ce que remet un professionnel — ou le livre original et sa traduction publiée sous forme de deux EPUB, alignés ici paragraphe par paragraphe d’après leurs longueurs : un paragraphe traduit a à peu près la longueur de sa source, et les rares fusions et scissions apparaissent comme le chemin le moins coûteux à travers la paire. Des paires alignées, il extrait les noms — une suite de mots à majuscule qui revient d’un côté, et ce qui revient avec elle de l’autre — et les propose au glossaire. Une majuscule en début de phrase n’est pas un indice, un nom doit revenir au moins trois fois, et
le Gardiencommele Gardien des maréessont proposés pour que les indices tranchent entre eux. Les propositions arrivent non acceptées et non verrouillées, par le même aperçu, les mêmes stratégies et le même écran que n’importe quel fichier de glossaire importé : un alignement est un indice, pas une décision. -
Le même livre dans une autre langue, sans le réimporter ni le réanalyser. Un livre est importé une fois, lu une fois et analysé une fois, et tout cela concerne la source : les chapitres, les passages, qui sont les personnages, quels liens les unissent, lesquels ont vu leur genre fixé par un lecteur. Seule la traduction appartient à une langue cible. Obtenir une version espagnole impliquait de réimporter le fichier et de payer l’analyse une seconde fois — et les deux traductions étaient ensuite en désaccord sur les noms, parce que rien ne les reliait. Traduire dans une autre langue crée un second livre à partir de la même source, en emportant les chapitres et leur carte, les passages, les personnages avec leurs alias et les décisions prises à leur sujet, les relations, la Book Bible, les mémoires d’analyse toujours rattachées à leurs propres passages, la feuille de style et le fichier source lui-même. Ce qui ne voyage jamais, c’est ce qui est écrit dans la première langue cible : les traductions, et le glossaire, dont les traductions sont dans cette langue et aucune autre. Les résumés rédigés par l’analyse restent dans la première langue — ils servent de contexte à un modèle, pas de texte à un lecteur — et un clone sans l’analyse est à une case à cocher près. Le nouveau livre démarre hors de toute série, car une série a une seule langue cible.
-
Un audit d’une série entière. Sept volumes traduits en un an, ce sont sept occasions d’appeler la même épée de deux noms, de donner à un personnage un genre que le tome 1 ne lui a jamais donné, ou de présenter les dialogues avec des tirets cadratins dans un volume et des guillemets dans le suivant. Rien n’est faux à l’intérieur d’un volume donné — et c’est exactement pourquoi rien ne l’a repéré : chaque vérification de Libris lisait un livre à la fois. L’onglet Cohérence d’une série les lit ensemble et signale un terme traduit de deux façons, un terme de série verrouillé qu’un passage traduit ne reprend pas (avec le passage), un personnage dont le genre ou le nom change d’un volume à l’autre, et deux volumes qui tranchent différemment le même champ de style là où la série ne tranche rien. Cela ne coûte aucun appel au modèle : tout ce qui est comparé est déjà enregistré. Appliquer à toute la série répond une fois pour toutes — la traduction choisie devient la décision verrouillée de la série et les volumes suivent, sauf ceux qui ont verrouillé la leur ou s’en écartent délibérément, qui sont comptés plutôt qu’écrasés ; un genre est fixé sur chaque fiche liée ; un champ de style passe à la série et les volumes le lui rendent. Un personnage nommé différemment est signalé mais jamais fusionné automatiquement : c’est une décision, et elle a sa place dans Identités. Une très longue série est lue jusqu’à une limite, et le rapport le dit plutôt que de prétendre avoir tout vu.
-
Ce que coûtera un livre, avant de l’importer. La dernière étape de l’assistant d’import indique désormais ce que contiennent les fichiers — mots, passages, chapitres —, ce qu’ils coûteraient avec chaque provider configuré, et quelle part du quota mensuel de la licence ils prendraient. Rien n’est créé et aucun modèle n’est appelé : les chiffres proviennent de l’inspection déjà faite et de l’historique du propriétaire avec ce provider quand il est suffisant, le même calcul que celui qu’a toujours utilisé l’estimation préalable à une opération payante. Les mots sont comptés comme la licence les décompte, si bien qu’un livre japonais n’est pas annoncé au tiers de son prix. Un livre qui ne tient pas dans ce qui reste du quota est signalé avant l’import plutôt qu’en pleine traduction. La vérification de cohérence globale est laissée de côté, et l’estimation dit qu’elle l’est : elle compte des termes et des personnages que l’analyse n’a pas encore découverts, et un chiffre inventé serait pire qu’une absence signalée.
-
Le genre d’un personnage, fixé une fois et accordé partout. Le français marque le genre sur les participes, les adjectifs et les pronoms, si bien qu’un personnage dont le genre est faux est faux dans chaque phrase qui le nomme — et jusqu’ici, le seul moyen de corriger cela était d’enregistrer la fiche entière, ce qui la fige : une fiche validée cesse d’apprendre, et l’analyse n’y ajoute plus ni relation, ni alias, ni ligne de description. Le genre et les pronoms peuvent désormais être fixés champ par champ : ces deux-là deviennent ceux du lecteur, le reste de la fiche continue d’évoluer. Le genre est une valeur plutôt qu’une phrase — masculin, féminin, non binaire, indéterminé — et quoi que réponde l’analyse, sa réponse est ramenée à l’une de ces quatre valeurs, afin que deux volumes d’une série puissent seulement être comparés. Un champ fixé est désigné comme tel dans le prompt et porte l’autorité d’une décision humaine : la traduction s’y accorde quoi que suggèrent les pronoms de la source, et la relecture signale un passage qui le contredit au lieu de le conserver. Fixer un champ renvoie en relecture les passages traduits qui nomment le personnage, comme le faisait déjà une décision de glossaire. Indéterminé est aussi une décision : un narrateur qui cache délibérément le genre d’un personnage, c’est un fait du livre, et la traduction doit laisser cette porte ouverte.
-
La feuille de style d’un livre, et de sa série. Le registre, le temps de la narration, les formes d’adresse, les honorifiques et la typographie des dialogues se décident une fois pour tout un livre, et c’est exactement ce que remarque un lecteur quand une machine hésite : un
vousqui devienttuentre deux chapitres, des guillemets qui changent de forme au troisième volume. Le dire signifiait auparavant un paragraphe de texte libre dans les instructions — lu comme de la prose, suivi ou non, impossible à comparer entre deux volumes et impossible à vérifier. C’est désormais une poignée de valeurs, dans les réglages du livre et dans ceux de la série : la série décide, un volume la surcharge champ par champ, et ce qui reste vide est laissé au modèle, exactement comme avant. Quelques personnages peuvent déroger à la règle générale — Mara et le Gardien se disenttualors que tous les autres disentvous. La feuille parvient au modèle sous forme de règle utilisateur, que les prompts traitent déjà comme l’autorité la plus haute qui soit, et la relecture signale ce qui s’en écarte. La typographie des dialogues, la seule décision qu’une machine peut vérifier seule, est contrôlée dans le texte traduit : un guillemet droit là où la feuille demande« »déclenche une alerte de relecture — sauf si la source elle-même en utilise un, car un livre a le droit de citer. Modifier une feuille renvoie en relecture les passages traduits que personne n’a validés. Migration de base de données.
[0.8.0] - 2026-09-20
Libris devient un logiciel sous licence. Une installation s’active une fois avec la clé que son lecteur a achetée, puis fonctionne grâce à un certificat que le serveur de licences signe et renouvelle. Cette version ajoute aussi le courriel — un livre terminé, un travail en attente —, la reprise par un modèle plus puissant d’une étape qui échoue sans cesse, l’auteur d’une série, et une vérification de configuration qui regardait au mauvais endroit. Libris est un logiciel propriétaire. Migration de base de données.
Avant de mettre à jour : cette version refuse, sans licence valide, le travail qui consomme des mots. Activez la vôtre dans Paramètres › Licence juste après le déploiement. Tout ce qui a déjà été produit reste lisible, exportable et supprimable dans tous les cas : un lecteur bloqué ne perd jamais un livre. L’image vient du registre auquel la licence donne accès : il faut indiquer une fois ce registre à une installation (voir Modifié).
Ajouté
- Une licence, et ce qu’elle permet. Une installation s’active avec la clé que son lecteur a achetée,
puis renouvelle d’elle-même un certificat Ed25519 — licence, formule, empreinte, quota et part consommée
de celui-ci — signé par le serveur et vérifié ici avec une clé publique qui est une constante du code
source. Le certificat vaut trois jours, soit aussi le délai de grâce dont dispose une installation quand
le serveur est injoignable : une panne n’interrompt jamais un lecteur, une révocation l’arrête au premier
renouvellement qui aboutit. Il nomme la machine pour laquelle il a été émis : le copier ne rapporte donc
rien. L’empreinte a deux moitiés : le
machine-idde l’hôte, qui change avec la machine et survit à un redéploiement, et un identifiant tiré au premier démarrage, qui suit une sauvegarde restaurée — c’est leur désaccord qui trahit une licence utilisée deux fois. Compose monte/etc/machine-iden lecture seule, faute de quoi chaque recréation ressemblerait à un déménagement. Ce qui est refusé sans licence valide, c’est le travail qui consomme des mots : un lancement, et chaque appel de modèle d’un travail en cours, qui se met alors en pause aveclicencepour motif. La lecture, l’export, la correction à la main et la suppression ne sont pas touchés. Le quota compte les mots de la source, une fois par passage, et une suite de caractères CJK compte pour un mot tous les deux caractères — sans quoi un livre japonais passerait presque gratuitement et sa traduction française serait facturée en entier. Quand le quota est atteint en plein livre, le livre en cours de traduction est terminé dans la limite deLICENCE_QUOTA_OVERRUN_WORDS, mais aucun nouveau travail ne démarre. Paramètres › Licence affiche la formule, la forme de la clé — jamais la clé —, les mots du mois face au quota, la durée de validité du certificat et le dernier contact ; c’est là qu’on active, qu’on renouvelle à la main et qu’on libère la machine avant un déménagement. Changer de licence se fait en une étape : saisir la nouvelle clé suffit, l’ancienne licence rend sa place d’elle-même pour rester utilisable ailleurs sans attendre le délai de déménagement, et la nouvelle clé est accordée avant que l’ancienne ne soit lâchée — une clé mal saisie ne coûte pas la licence qui fonctionnait. Voir la configuration. - Libris écrit quand un livre est terminé, et quand un travail attend. Une traduction prend des heures et personne ne reste devant : il n’y avait aucun moyen d’apprendre qu’un livre était terminé — ou, pire, qu’un travail s’était arrêté deux heures plus tôt dans l’attente d’une décision dont personne ne savait qu’elle était nécessaire. Quatre messages, et une règle : un message part quand quelque chose s’est terminé ou va s’arrêter, jamais quand quelque chose a simplement commencé. Un livre terminé ; un travail arrêté et en attente (budget, analyse inutilisable, licence — pas une panne, qui se relance d’elle-même) ; le quota du mois à quatre-vingts pour cent, une fois ; et un certificat que personne n’a réussi à renouveler depuis un jour, le cas qu’on ne remarque jamais parce que l’installation continue de fonctionner jusqu’au moment où elle s’arrête. Le silence est la règle par défaut : non pas un réglage à désactiver, mais l’absence d’adresse. Une installation qui passe à cette version démarre en silence ; un lecteur indique une adresse dans Mon compte › Notifications, désactive ce qu’il ne veut pas et choisit le français ou l’anglais. Rien n’est envoyé depuis une requête : le message est écrit dans la même transaction que ce qu’il annonce, et le worker vide la file avec des nouvelles tentatives de plus en plus espacées. Voir la configuration.
- La traduction d’un seul chapitre. Un volume suivi pendant des mois compte des centaines de chapitres, et télécharger le livre entier pour relire celui qui vient d’être terminé n’a aucun sens. Le menu de chapitre de l’éditeur télécharge désormais ce chapitre seul, en texte ou en Markdown, dans un fichier nommé d’après lui plutôt que d’après le livre. Seulement un chapitre réellement traduit : en rendre un qui ne l’est pas mettrait l’original à la place de la traduction ; Libris refuse donc et indique combien de passages manquent encore.
- Une étape qui échoue sans cesse est reprise par un modèle plus puissant.
AUTOPILOT_ESCALATION_PROVIDERdésigne le provider qui prend le relais quand une étape échoueAUTOPILOT_ESCALATE_AFTERfois sur lesAUTOPILOT_ESCALATE_WINDOWdernières. Seule cette étape change de provider : les suivantes restent sur celui du livre. Contrairement à la chaîne de repli, il ne s’agit pas d’un provider en panne, mais d’un provider incapable de mener à bien cette étape précise. - L’auteur d’une série.
series.authorsreste ce que disent les volumes, reconstruit à chaque analyse ;series.authorest ce que le lecteur a décidé, et il nomme les volumes qui ne portent pas d’auteur à eux.
Modifié
- Libris est un logiciel propriétaire.
LICENSEporte une mention propriétaire, en français et en anglais, et dit ce dont un lecteur a réellement besoin : ce que vous traduisez vous appartient, et rien n’en quitte jamais votre serveur — le serveur de licences voit une empreinte de machine et un nombre de mots ; et sans licence valide, Libris cesse de traduire mais continue de rendre ce qu’il a déjà produit, si bien qu’aucun livre n’est jamais perdu. Les labels de l’image, les trois manifestes de paquets et le document OpenAPI déclarentLicenseRef-Proprietary, etscripts/check_version.pyfait échouer le build si l’un d’eux cesse de le dire. - EbookLib quitte l’image. Elle est sous AGPL, c’était une dépendance d’exécution, et elle voyageait
donc dans une image propriétaire. Rien dans
app/ne l’a jamais importée : elle construisait les EPUB que lisent les tests, ainsi qu’une fixture livrée dans l’image (scripts/check_epubcheck.py), désormais douze lignes dezipfileet de XML vérifiées avec le vrai EPUBCheck — le livre valide passe toujours, le livre cassé déclenche toujoursRSC-007. EbookLib passe dans l’extratest, etsixpart avec elle. - L’image vient du registre auquel votre licence vous donne accès.
scripts/install-docker.shprend son registre dansLIBRIS_REGISTRYou dans le.envécrit par une installation précédente, le conserve lors d’un changement de version, et indique où l’écrire quand il n’a rien à installer. Il faut indiquer une fois son registre à une installation existante : mettez l’adresse dansLIBRIS_IMAGEdans.env, ou passezLIBRIS_REGISTRYà l’installateur. Acheter une licence vous donne trois choses — la clé, l’adresse du registre et les identifiants pour y tirer l’image.
Corrigé
librisctl doctorcomparait la mauvaise chose. Il regardait l’âge d’un conteneur plutôt que ce qu’il contient : un conteneur de base de données plus ancien que la dernière modification du.envétait signalé comme périmé alors qu’il n’avait jamais porté la variable modifiée. Chaque variable du fichier est désormais comparée à ce que le conteneur a réellement reçu, et le rapport nomme le service sans jamais afficher de valeur.