Dans un retour d’évaluation par lot, un élément a changé case_id de gold-pair-078 à gold-pair-079, tandis que son identifiant de tâche désignait toujours le cas initial. Les champs reconstruits depuis la trace d’échec sont :
task_id: gold-pair-078::gold-pair-078-candidate-127
candidate_id: gold-pair-078-candidate-127
case_id: gold-pair-079
Cet élément appartenait à un lot de 20 candidats. Le JSON était lisible et le contrôle structurel passait. La vérification individuelle a ensuite détecté l’erreur, alors que le reçu du lot portait déjà status: ok. Trace originale et emplacement du code
L’évaluation formelle n’a pas été achevée. Mais la reprise devenait ambiguë : le « succès » de l’ancien fichier contredisait l’échec ultérieur. Un programme qui importait les seuls reçus réussis pouvait accepter de nouveau ce lot.
La correction était nette : enregistrer le succès après validation de l’identité de tous les éléments. L’appelant connaît déjà la tâche à laquelle appartient une demande. Le programme doit la comparer au retour, plutôt que confier cette garantie au modèle.
Accepter le lot entier, puis écrire le succès
Un schéma qui définit uniquement types et structure accepte deux chaînes différentes. Un schéma dynamique peut contraindre les valeurs d’identité ; notre système compare également le retour aux demandes effectives pour accepter le lot.
L’implémentation actuelle contrôle successivement case_id de premier niveau, couverture des tâches, structure des éléments et identité. La couverture compare quantité et ensemble pour détecter manques, doublons et ajouts. L’identité vérifie task_id, case_id, candidate_id et le type du candidat.
Voici l’ordre essentiel sous forme pédagogique. L’implémentation de production contient aussi schémas de phase, reçus et gestion des nouvelles tentatives.
expected = {task["task_id"]: task for task in requests}
if len(expected) != len(requests):
raise InvalidBatch("La demande contient des tâches en double")
ids = [item["task_id"] for item in response["items"]]
if len(ids) != len(expected) or set(ids) != set(expected):
raise InvalidBatch("Tâches manquantes, dupliquées ou ajoutées")
for item in response["items"]:
task = expected[item["task_id"]]
for key in ("task_id", "case_id", "candidate_id"):
if item[key] != task[key]:
raise InvalidBatch(f"Identité incohérente : {key}")
commit_success(response)
L’association par identifiant permet de changer l’ordre des retours. La comparaison des champs redondants évite qu’un module rattache le même objet à 078 via task_id et un autre à 079 via case_id.
Le programme ne remplace pas simplement 079 par 078. Le décalage seul ne révèle pas si le modèle a mal copié un identifiant ou répondu à une autre question. Échouer le lot et conserver le retour brut permet d’enquêter sur les deux hypothèses.
Cette acceptation globale a un coût : les 19 autres éléments apparemment corrects ne sont pas réutilisés. En échange, la frontière d’enregistrement reste simple. Une acceptation partielle demanderait validation indépendante, complétion des manques et traitement des soumissions répétées pour chaque élément : une autre conception de reprise.
Revérifier les anciens fichiers réussis
Corriger les nouveaux appels laisse subsister les anciens reçus. L’import vérifie donc lui aussi chaque élément. Lorsqu’il retrouve l’erreur d’identité correspondant à l’ancien journal d’échec, le lot entier reste un matériau de diagnostic et aucun élément n’entre dans un point de reprise réutilisable.
Le coût des appels effectués reste comptabilisé. Un redémarrage peut changer de répertoire, pas effacer les essais précédents. Sinon, le coût annoncé par résultat utilisable ne comprendrait que la dernière tentative réussie.
La taille des lots doit refléter ce coût total. Les grands lots mutualisent l’entrée commune ; leur répétition amplifie aussi une erreur individuelle. Le projet a ensuite autorisé une division déterministe uniquement pour certains lots ayant épuisé leurs tentatives, en laissant encore un échec individuel terminer l’exécution. La division reste une reprise bornée, pas une raison de relancer sans fin.
Le test de régression altère volontairement l’identité d’un élément du premier retour et vérifie trois choses : un reçu d’échec, aucun point de reprise réussi, puis l’écriture du succès uniquement après un retour correct. Il teste précisément la brèche empruntée par l’incident.
Le compteur des lots terminés doit augmenter à cet endroit : retour rattaché aux demandes, acceptation globale terminée, puis enregistrement du succès.