Codex vs Claude : il ne s'agit pas tant de désigner un vainqueur universel que de choisir le mode de fonctionnement auquel vous pouvez faire confiance au quotidien. Ces deux produits permettent d'inspecter un dépôt, de modifier plusieurs fichiers, d'exécuter des commandes, de lancer des tests et d'expliquer un correctif. Les différences significatives résident dans la manière dont vous déléguez le travail, la fréquence à laquelle vous intervenez pour orienter l'agent, la quantité de données que vous pouvez examiner et la façon dont chaque outil s'intègre à votre environnement de développement existant.
Lors de notre test contrôlé sur un référentiel comprenant quatre tâches, Codex a obtenu un score de 98/100 et Claude Code, un score de 99/100. Les deux ont accompli le travail essentiel. Claude Code a fait preuve d’une analyse plus approfondie et d’une meilleure couverture des cas limites, tandis que Codex a souvent atteint le résultat requis avec une portée plus restreinte et a produit des preuves d’exécution plus solides dans notre configuration. Une différence d’un point sur un petit test Python ne suffit pas pour désigner un vainqueur absolu.
Les développeurs qui ne souhaitent pas que le reste de leur flux de travail soit lié à un seul agent de codage peuvent ajouter GlobalGPT en tant que couche multimodèle et multimodale distincte. GlobalGPT intègre plus de 100 modèles de pointe, tels que GPT 5.6, Claude Opus 5 et GPT Image 2, dans un seul tableau de bord. De plus, le GlobalGPT CLI, les parcours MCP et Skill peuvent être utilisés à partir de Codex ou du code Claude pour obtenir des avis complémentaires, planifier, documenter ou exploiter d'autres modèles pris en charge, tandis que l'hôte de codage natif conserve le contrôle des modifications apportées au référentiel et des tests.

Cette comparaison associe des informations issues des plans officiels, un travail pratique sur les référentiels, des résultats complets et évolutifs, ainsi que des retours d'expérience clairement identifiés par la communauté. L'objectif est d'aider un développeur indépendant à choisir un outil de développement principal sans se perdre dans les subtilités de l'accès par abonnement, des crédits supplémentaires et de la facturation des API.
Codex vs Claude : le code en bref
| Facteur déterminant | Codex | Claude Code |
|---|---|---|
| Travaux relatifs au référentiel principal | Lit, modifie, exécute des commandes et vérifie les modifications sur toutes les interfaces Codex prises en charge | Agent de terminal interactif permettant de lire, de modifier, d'exécuter des commandes et de vérifier les modifications |
| Style observé lors de notre test | Plus concis dans certaines parties relatives à la mise en œuvre et à la correction des bogues | Une analyse plus approfondie des dépôts, des tests et de l'étendue des revues |
| Compréhension du référentiel | Lien fonctionnel avec la tâche gelée | |
| Examen du code | Deux défauts valides présentant un niveau de gravité plus élevé ont été détectés et corrigés | A signalé davantage de problèmes reproductibles et a fait passer la note de 19/20 à 18/20 |
| Vitesse observée | Résultats mitigés ; les conditions n'étaient pas suffisamment comparables pour désigner un vainqueur incontestable. | |
| Gamme d'entrée de gamme grand public | $20/mois dans le cadre du plan ChatGPT correspondant | Claude Pro : $20 par mois aux États-Unis |
| Niveaux de consommation plus élevés | Niveaux $100 et $200 | Max. 5x à $100 et max. 20x à $200 |
Ce tableau présente une décision d'achat et non un classement des modèles. Des paramètres de modèle, un référentiel, une configuration des autorisations ou une spécification de tâche différents peuvent modifier le résultat. Si vous utilisez déjà un produit, la meilleure comparaison consiste à utiliser une tâche délimitée issue de votre propre base de code, avec la même commande de réussite et sans relance de qualité.
Profil d'essai contrôlé
Premier résultat valide, selon la même grille d'évaluation fixe. Les barres sont normalisées par rapport à la note maximale de chaque tâche.
Le graphique montre d'où provient cette différence d'un point ; il ne transforme pas un petit match en classement général.
Qu'est-ce que le Codex et le code Claude ?
« Codex » et « Claude Code » sont des produits d'agent, et non de simples noms de modèles. Le concept sous-jacent Modèle d'IA pour le codage C'est important, mais l'environnement qui l'entoure détermine également quels fichiers l'agent peut consulter, quelles commandes il est autorisé à exécuter, comment fonctionnent les validations, comment le contexte est conservé et quelles données sont conservées une fois la tâche terminée. Se limiter à comparer la réputation des modèles revient à ignorer une grande partie de l'expérience que le développeur acquiert.
Codex couvre les flux de travail en ligne de commande, en IDE, sur ordinateur de bureau et orientés cloud. Cette polyvalence le rend adapté aussi bien à la collaboration locale directe qu’à une délégation plus ciblée. Claude Code s’articule autour d’un flux de travail conversationnel en terminal, avec des intégrations prises en charge et de nombreuses possibilités de personnalisation ; cela Guide d'utilisation de Claude pour le codage offre une introduction plus complète à ce flux de travail. Pour certains développeurs, observer le fonctionnement d’un agent dans le terminal est rassurant. Pour d’autres, ce sont le diff final, les tests et la piste d’audit qui constituent les éléments essentiels, plutôt qu’un échange continu.
Cette distinction explique également pourquoi deux tests utilisant des modèles théoriquement performants peuvent donner des résultats différents. C'est l'hôte qui détermine la manière dont les instructions sont présentées, comment les outils sont appelés et à quel moment un humain doit valider une action. Les comparaisons au sein de la communauté qui ne tiennent pas compte de ce cadre de test risquent de confondre un comportement observé au niveau du produit avec une vérité au niveau du modèle.
- Le modèle offre des capacités de raisonnement et de génération.
- Le harnais de l'agent gère les fichiers, les commandes, le contexte, les validations et la restauration.
- Le contrat de mission de l'utilisateur détermine le champ d'application, les critères de réussite et le moment où l'agent doit s'arrêter.

Processus de travail et pilotage : délégation ou accompagnement continu ?
La question la plus pertinente concernant le Codex et le code Claude n'est souvent pas “ Lequel permet d'écrire un meilleur code ? ”, mais “ Comment est-ce que je souhaite l'utiliser ? ” Une tâche claire et bien délimitée peut être déléguée avec un objectif précis, un périmètre défini et une commande de vérification. Une refactorisation ambiguë nécessite une discussion, une inspection intermédiaire et la possibilité de réorienter l'agent avant qu'il n'apporte trop de modifications.
La gestion continue s'avère utile lorsque les exigences évoluent ou que les choix architecturaux font encore l'objet de discussions. Elle devient un surcoût lorsque l'agent sollicite à plusieurs reprises des décisions qui auraient pu être prises à partir des instructions du référentiel. L'exécution autonome est utile lorsque le cahier des charges de la tâche est stable. Elle devient risquée lorsque l'agent émet des hypothèses non vérifiées ou élargit le périmètre de la tâche sans disposer d'une procédure de retour en arrière claire.
Un rapport détaillé publié sur Reddit le 13 avril 2026 décrivait environ 100 heures passées avec Claude Code et 20 heures avec Codex sur un projet Python et TypeScript d’environ 80 000 lignes comprenant quelque 2 800 tests. L'auteur a qualifié Claude de plus rapide et plus interactif, mais nécessitant davantage de surveillance, et Codex de plus lent et plus réfléchi. Ce rapport est particulièrement utile car il inclut le contexte du projet et de l'expérience, mais il ne représente néanmoins que le flux de travail d'un seul développeur.

Nos propres chronométrages n’ont pas permis de désigner un vainqueur incontestable. Claude a terminé les deux premières tâches plus rapidement, tandis que Codex a terminé les deux dernières plus rapidement. Claude a également eu recours à un sous-agent de secours lorsque son chemin d’authentification CLI était indisponible ; les parcours d’exécution n’étaient donc pas équivalents à ceux du laboratoire. La conclusion qui s'impose est que la vitesse dépend de la tâche, du modèle sélectionné, du niveau d'effort, du contexte et de l'hôte — et non pas que l'un ou l'autre des produits soit systématiquement plus rapide.
Compréhension du référentiel et gestion du contexte
La compréhension d'un référentiel ne se limite pas à la simple dénomination des dossiers. Un agent efficace doit suivre le parcours des données d'un fichier à l'autre, identifier les contraintes qui limitent une modification, localiser les tests, distinguer un symptôme de sa source probable et expliquer le risque lié à la modification d'une couche inappropriée. Une cartographie exhaustive peut révéler des incohérences cachées ; une cartographie concise peut permettre à un développeur de prendre plus rapidement une décision de mise en œuvre sûre.
Dans notre tâche T1 en lecture seule, les deux agents ont obtenu un score de 20/20 et ont étayé leurs réponses à l’aide du référentiel. Le code Claude s’est révélé plus exhaustif et a mis en évidence des incohérences supplémentaires dans les contrats. Codex s’est montré plus concis tout en identifiant les fichiers pertinents, les risques et le plan de mise en œuvre. Aucun des deux styles n’est automatiquement supérieur. L’exhaustivité est utile lors de migrations et d’audits dans un contexte inconnu ; la concision est utile lorsque le développeur connaît déjà l’architecture et souhaite un plan de changement ciblé.
T1 · Test du référentiel contrôlé
Se familiariser avec un référentiel que l'on ne connaît pas avant de le modifier
Cartographier l'architecture, suivre le flux de données, identifier les risques liés aux fonctionnalités prioritaires, sans apporter aucune modification aux fichiers.
Architecture : modèle, référentiel, service et utilitaire de gestion du temps non connecté. Principaux risques : sémantique des priorités non définie, compatibilité, ordre d'exécution, validation et incompatibilité de portée.
Avis du critique : Concis, étayé par des éléments concrets et suffisant pour prendre la décision en suspens.
Trois couches plus un module isolé. Pas de boucles ; injection de dépendances minimale. Cela a également mis en évidence l'attribution des identifiants, les contrats d'erreur asymétriques et une couverture de test insuffisante.
Avis du critique : Plus exhaustif tout en respectant le même contrat de lecture seule.
Afficher l'intégralité des résultats de Codex
Sortie complète, validée et aseptisée
Architecture ##
Il s'agit d'un petit module Python utilisant uniquement les bibliothèques standard et comportant quatre couches fonctionnelles :
- **Modèle de données :** [`Job`]() est une classe de données immuable contenant `identifier`, `name` et `owner`. La méthode `Job.to_dict()` la sérialise via `dataclasses.asdict()`.
- **Référentiel :** [`JobRepository`]() stocke les tâches dans un dictionnaire en mémoire dont les clés sont les identifiants. Il n’y a ni base de données ni persistance durable.
- **Service :** [`SchedulerService`]() gère l’attribution des identifiants, la normalisation des entrées, la création, la liste et la suppression des tâches.
- **Utilitaire de temps :** [`next_daily_run()`]() calcule l’heure de l’exécution suivante, mais aucune fonction ne l’importe ni ne le relie à `Job`, `SchedulerService` ou `JobRepository`.
- **API publique :** [`scheduler.__init__`]() n’exporte que `SchedulerService`.
Malgré le nom du référentiel, les tâches ne contiennent actuellement aucune information de planification, et il n’existe pas de file d’attente d’exécution. La priorité peut donc affecter les métadonnées stockées et l’ordre d’affichage, mais elle ne peut pas influencer l’exécution effective des tâches sans élargir considérablement le système.
## Flux de données de création et d’affichage
Création via `SchedulerService.create_job(name, owner)` :
1. [`create_job()`]() rejette un nom composé uniquement d’espaces.
2. Il tronque `name` et `owner`, puis construit un objet `Job` immuable en utilisant le `_next_identifier` du service.
3. [`JobRepository.save()`]() enregistre l’objet dans `_jobs[job.identifier]`.
4. Le service incrémente `_next_identifier` et renvoie le même `Job`.
Liste via `SchedulerService.list_jobs()` :
1. [`list_jobs()`]() délègue directement à `repository.all()`.
2. [`JobRepository.all()`]() trie les clés du dictionnaire par ordre numérique.
3. Les tâches sont donc renvoyées par ordre croissant d’identifiant/de création, et non par ordre de planification ou de priorité.
## Fichiers susceptibles d’être affectés par les priorités des tâches
Obligatoire :
- [`scheduler/models.py`]() : ajouter le champ " priority " et une valeur par défaut éventuelle. `to_dict()` l’inclura automatiquement car il utilise `asdict()`.
- [`scheduler/service.py`]() : accepter, valider et transmettre la priorité à `Job`.
- [`tests/test_scheduler.py`]() : tester les cas par défaut, explicites, non valides, sérialisés et de classement.
Conditionnel :
- [`scheduler/repository.py`]() : ne modifier `all()` que si les priorités sont destinées à contrôler l’ordre d’affichage. Une clé secondaire déterministe telle que `identifier` devrait gérer les ex aequo.
- [`scheduler/__init__.py`]() : à mettre à jour uniquement si la priorité devient une énumération publique ou un objet valeur.
- [`README.md`]() : documenter les valeurs acceptées, la valeur par défaut et la sémantique de classement.
Probablement non concerné :
- `scheduler/time_rules.py`, car son seul symbole opère sur une date-heure fournie et n’a aucun rapport avec les tâches ou le classement.
## Risques majeurs
- **Sémantique non définie :** le code ne fournit aucun indice permettant de déterminer si des valeurs plus grandes ou plus petites correspondent à une priorité plus élevée, quelles valeurs sont valides, ou si la priorité a une incidence sur le classement.
- **Compatibilité :** L’ajout d’un argument obligatoire à `Job` ou à `create_job()` casserait les appels existants, tels que `create_job("Daily report", "Alex")` dans le test actuel. Une valeur par défaut permettrait de préserver cet appel.
- **Problème lié à la construction par position :** `Job` est actuellement construit par position dans `SchedulerService.create_job()`. Le placement des champs et les futurs appels par position pourraient attribuer silencieusement des valeurs erronées ; une construction par mots-clés serait plus sûre.
- **Modification de l’ordre :** Le remplacement de l’ordre des identifiants dans `JobRepository.all()` modifie le comportement établi. Les priorités égales nécessitent un critère de départage stable.
- **Ambiguïté de validation :** Une valeur Python non restreinte pourrait autoriser des chaînes de caractères, des booléens ou des entiers arbitraires difficiles à comparer de manière cohérente.
- **Incohérence au niveau de la portée d’exécution :** il n’existe ni répartiteur ni file d’attente d’exécution. L’affirmation selon laquelle la priorité détermine quel travail s’exécute en premier ne serait étayée par aucun symbole actuel.
- **Limitations en mémoire :** la priorité, comme tous les autres champs de tâche, disparaît à la fin du processus, car `_jobs` n’est qu’un dictionnaire d’instance.
## Plan de mise en œuvre et de validation
1. Définir d’abord le contrat : représentation, valeurs autorisées, valeur par défaut, sens de la priorité, règle de départage et indication précisant si cela modifie l’ordre d’affichage.
2. Ajouter `priority` à `Job`, de préférence avec une valeur par défaut rétrocompatible.
3. Étendre `SchedulerService.create_job()` avec un paramètre de priorité par défaut, le valider, puis construire `Job` à l’aide d’arguments-clés.
4. Si le classement tient compte de la priorité, modifier `JobRepository.all()` pour trier d’abord par priorité, puis par identifiant. Sinon, laisser l’ordre du référentiel inchangé.
5. Ajouter des tests pour :
- La création existante à deux arguments.
- La préservation explicite de la priorité.
- La priorité par défaut.
- Types non valides et valeurs hors plage.
- Sortie de `Job.to_dict()`.
- Ordre d’affichage en cas de priorités multiples.
- Ordre stable pour des priorités égales.
- Comportement actuel en cas de nom vide.
6. Mettre à jour le fichier README avec le contrat public exact.
7. Exécuter la suite de tests hors ligne complète avec `python3 -m unittest discover -s tests -v`.
## Vérification effectuée
- Suite de tests de référence : **2 tests réussis**.
- La recherche de symboles à l’échelle du référentiel a confirmé que `next_daily_run()` est déconnecté et qu’il n’existe aucun symbole de priorité.
- Fichiers modifiés : **aucun**.
- Implémentation de la fonctionnalité : **non effectuée**, comme requis.
> **Conclusion + décision**
>
> La modification est mineure si la priorité ne concerne que les métadonnées ou l’ordre d’affichage : principalement `models.py`, `service.py`, `repository.py` et les tests. Avant la mise en œuvre, il convient de déterminer si la priorité décrit simplement une tâche ou si elle modifie l’ordre de `list_jobs()`, ainsi que l’échelle de valeurs, la valeur par défaut, la direction et la règle de départage.Afficher l'intégralité du code de sortie Claude
Compte rendu complet du transfert, y compris la transcription mot pour mot de la première sortie valide
# T1 Journal d'exécution — Compréhension d'un référentiel inconnu
## Paramètres d'exécution
| Champ | Valeur |
| --- | --- |
| Tâche | `T1` |
| Invite figée | `01-prompts/T1.md` |
| SHA-256 de la prompt gelée | `a571ff15c2502ec29b172ae2e77dd9ab0caca2869b91f9468d47571434d16c17` |
| Unité d’exécution | sous-agent Claude isolé, `usage général`, contexte vierge |
| Méthode d’isolation | **repli sur un sous-agent** (rétrogradation documentée — voir `results/isolation-decision.md`) |
| Copie propre attribuée | `runtime/workspaces/T1` |
| Version du code Claude | `2.1.220` |
| Paramétrage du modèle | `claude-opus-5` |
| start_utc | `2026-07-28T10:27:31Z` |
| end_utc | `2026-07-28T10:28:32Z` |
| Durée | 61 s (en parallèle avec T2–T4 ; mesure de latence non fiable) |
| Numéro de tentative | 1 |
| Statut | `valide` |
| Intervention humaine | aucune |
## Résumé de l’outil Safe
`date`, `find`, `ls`, `wc`, `stat`, `grep`, `Read` sur 7 fichiers de l'espace de travail, `python3 -V`,
`python3 -m unittest discover -s tests -v`. Toutes les lectures sont confinées à l'espace de travail attribué.
Pas de réseau, pas d’installations, pas d’écritures.
## Résultat de la vérification hors ligne
`python3 -m unittest discover -s tests -v` → 2 tests, OK (sortie 0). Vérification effectuée par le
coordinateur depuis l’extérieur de l’espace de travail : voir `results/checks/T1-public.txt`.
## Correctif
Aucun. `results/T1/patch.diff` est vide, et `diff -ru 02-fixture runtime/workspaces/T1`
ne renvoie aucune différence. La tâche nécessitait une inspection sans modification des fichiers ; ceci est
confirmé plutôt qu’affirmé.
## Erreurs corrigées
Une erreur de shell récupérable : un `grep` initial utilisait des motifs `--include=*.py` non entre guillemets que
le shell a tenté d’interpréter comme des expressions globales ; la commande a été réexécutée avec des motifs entre guillemets et a abouti. Aucun effet sur les résultats.
## Sortie visible (mot pour mot)
### 1. Description de ce dépôt
Un fixture autonome de la bibliothèque standard Python nommé `local-scheduler-1.0.0` (`fixture-manifest.json`), sous licence MIT, sans dépendance réseau ni de production (`README.md`, `"network_required": false`). Il est très léger : 8 fichiers source/doc plus le manifeste, soit 103 lignes au total. L’interpréteur utilisé est **Python 3.9.6**. Il n’y a ni `pyproject.toml`, ni `setup.py`, ni configuration CI, ni linter, ni configuration de vérificateur de types — le seul workflow déclaré est `python3 -m unittest discover -s tests -v` (`README.md`).
### 2. Architecture
Trois couches plus un module orphelin, tous sous `scheduler/` :
| Couche | Fichier | Symbole | Responsabilité |
|---|---|---|---|
| Façade du paquet | `scheduler/__init__.py` | `__all__ = ["SchedulerService"]` | Réexporte uniquement `SchedulerService` ; `Job`, `JobRepository` et `time_rules` ne font pas partie de l’interface publique |
| Modèle de domaine | `scheduler/models.py` | `Job` (`@dataclass(frozen=True)`) | Objet de valeur immuable avec les champs `identifier: int`, `name: str`, `owner: str`, ainsi que `to_dict()` implémenté sous la forme `asdict(self)` |
| Persistance | `scheduler/repository.py` | `JobRepository` | `dict` en mémoire dont les clés sont des identifiants ; `save`, `get`, `all`, `delete` |
| Service d’application | `scheduler/service.py` | `SchedulerService` | Validation, attribution d’identifiant, orchestration : `create_job`, `list_jobs`, `delete_job` |
| Orphelin | `scheduler/time_rules.py` | `next_daily_run` | Calcul de récurrence — **n'est importé par aucun fichier** |
Le sens des dépendances est clair et unidirectionnel : `service.py` importe depuis `.models` et `.repository` ; `repository.py` importe depuis `.models` ; `models.py` n’importe que des `dataclasses`. Aucun cycle. L’injection de dépendances est présente mais minimale — `SchedulerService.__init__(self, repository=None)` effectue `self.repository = repository or JobRepository()`, ce qui permet de substituer un faux référentiel lors des tests.
Notez que `scheduler/time_rules.py` est aujourd’hui du code mort. J’ai recherché `time_rules` et `next_daily_run` dans l’arborescence complète ; les seuls résultats sont sa propre définition et sa mention dans `expected_files` du fichier `fixture-manifest.json`. Il est livré mais n’est pas connecté.
### 3. Flux de données
**Création d’une tâche** — `SchedulerService.create_job(name, owner)` :
1. Contrôle : `if not name.strip(): raise ValueError('name is required")`. Il s’agit de la *seule* validation du système — `owner` n’est jamais vérifié, donc un propriétaire vide est accepté.
2. Construction : `Job(self._next_identifier, name.strip(), owner.strip())` — construction par position, et les deux chaînes sont normalisées par suppression des espaces.
3. Persistance : `self.repository.save(job)`, qui effectue `self._jobs[job.identifier] = job` et renvoie le job.
4. Incrémentation du compteur : `self._next_identifier += 1` — *après* l’enregistrement ; ainsi, si une exception est levée, le compteur reste inchangé.
5. Retour de l’instance `Job` (le service renvoie son propre `job` local, et non la valeur de retour du référentiel).
L’attribution des identifiants se fait au niveau du **service**, et non du référentiel (`self._next_identifier = 1` dans `SchedulerService.__init__`). Il s’agit là d’un point de jonction important : l’injection d’un référentiel contenant déjà des tâches les écrasera silencieusement, car le nouveau service recommence la numérotation à 1.
**Liste des tâches** — `SchedulerService.list_jobs()` est un simple passage vers `JobRepository.all()`, qui renvoie `[self._jobs[key] for key in sorted(self._jobs)]`. Le tri s’effectue donc **par ordre croissant selon l’identifiant entier**, ce qui correspond actuellement à l’ordre d’insertion. Une nouvelle liste est construite à chaque appel, mais les objets `Job` sont des références partagées — ce qui n’est sans risque que parce que `Job` est gelé.
**Suppression** — `SchedulerService.delete_job(identifier)` délègue à `JobRepository.delete`, qui correspond à `self._jobs.pop(identifier)` sans valeur par défaut, ce qui lève une exception `KeyError` en cas d’identifiant manquant. Cela est incohérent avec `JobRepository.get`, qui renvoie `None` dans la même situation.
**Couverture de test de ces chemins** — `tests/test_scheduler.py` comporte exactement deux cas : `test_create_and_list_jobs` (vérifie que `job.identifier == 1` et que `[job] == service.list_jobs()`) et `test_blank_name_is_rejected`. Les deux réussissent sur l’arborescence actuelle.
### 4. Fichiers susceptibles d’être affectés par l’ajout de priorités aux tâches
Par ordre décroissant de certitude :
1. **`scheduler/models.py`** — certain. `Job` a besoin d’un champ `priority`. Comme la classe de données est définie avec `frozen=True` et que les champs sont positionnels, un nouveau champ doit comporter une valeur par défaut (par exemple `priority: int = 0`) ou être placé après les trois champs existants, sinon toutes les constructions positionnelles existantes seront rompues. `to_dict()` ne nécessite aucune modification — `asdict(self)` récupère automatiquement le champ, ce qui constitue un changement silencieux du contrat de sérialisation plutôt qu’une modification du code.
2. **`scheduler/service.py`** — certain. `create_job` nécessite un paramètre `priority` et doit le transmettre au constructeur positionnel `Job(...)` à la ligne 13. Si la priorité est validée (plage, appartenance à une énumération), la condition de validation doit être placée à côté de la vérification existante `name.strip()`. Si la liste doit être triée par priorité, c’est dans `list_jobs` qu’il faudrait implémenter une politique de tri si l’on souhaite que le référentiel reste un simple magasin de données.
3. **`scheduler/repository.py`** — probable. La méthode `sorted(self._jobs)` de `JobRepository.all()` trie les *clés* du dictionnaire, c'est-à-dire les identifiants. Un classement par priorité nécessite de modifier cela pour trier les valeurs selon une clé telle que `(-job.priority, job.identifier)`, ou d'ajouter un accesseur ordonné distinct. Ne laissez pas le dénouement en cas d’égalité implicite : l’ordre d’insertion dans le dictionnaire n’est pas un contrat stable sur lequel on peut compter.
4. **`tests/test_scheduler.py`** — certain. Nouveaux cas pour la priorité par défaut, la priorité explicite, le classement et le rejet des priorités invalides. Notez que l’expression existante `assertEqual([job], service.list_jobs())` compare le *même* objet ; elle résiste donc à l’ajout d’un champ ; elle ne résisterait pas si elle comparait un littéral `Job` nouvellement construit.
5. **`README.md`** — probablement, si la sémantique des priorités (quelle extrémité de la plage l’emporte, valeur par défaut) doit être mentionnée quelque part.
6. **`scheduler/__init__.py`** — uniquement si une énumération de priorités ou des constantes doivent être exportées avec `SchedulerService`.
7. **`fixture-manifest.json`** — uniquement si vous ajoutez un nouveau fichier de module ; son tableau `expected_files` constitue un inventaire explicite et risquerait de devenir obsolète.
8. **`scheduler/time_rules.py`** — ne doit *pas* être modifié. La priorité est orthogonale à la récurrence, et ce module n’est pas connecté.
### 5. Risques majeurs
- **La sémantique de tri constitue un changement de comportement silencieux.** `JobRepository.all()` garantit actuellement un ordre croissant des identifiants et `list_jobs` en hérite. Tout utilisateur s’appuyant sur cette garantie verra son code ne plus fonctionner en cas de reclassement. Il faut décider explicitement : est-ce que `list_jobs()` change de signification, ou est-ce qu’une nouvelle fonction `list_jobs_by_priority()` apparaît à côté ? La première option est la plus risquée et le test existant `test_create_and_list_jobs` est trop faible pour détecter une régression (liste à un seul élément).
- **Le sens du tri est véritablement ambigu.** La " priorité 1 ' signifie conventionnellement *la plus élevée* dans certains systèmes et *la plus faible* dans d’autres. Il n’y a rien dans ce dépôt — ni commentaire, ni chaîne de documentation, ni ligne dans le README — qui permette de trancher. Choisissez une convention, documentez-la dans `models.py`, et encodez-la dans un test comportant au moins trois priorités distinctes afin que le sens du tri soit clairement défini.
- **Égalité instable lors du tri.** Si deux tâches partagent la même priorité, le résultat doit néanmoins être déterministe. La fonction `sorted` de Python est stable, mais cette stabilité n’est utile que si l’ordre d’entrée est lui-même défini. Incluez toujours `identifier` comme clé secondaire explicite.
- **Ordre des champs dans une dataclass gelée.** `Job` est une `dataclass` avec `@dataclass(frozen=True)` comportant trois champs positionnels, et `service.py:13` le construit de manière positionnelle. Insérer `priority` à un autre emplacement que le dernier, ou sans valeur par défaut, constitue un changement de compatibilité que les deux tests existants pourraient ne pas signaler clairement.
- **Élargissement du contrat de `to_dict()`.** `asdict(self)` reflète tous les champs. L’ajout de `priority` modifie chaque charge utile sérialisée sans modification visible du corps de la méthode dans `models.py`. Tout ce qui vérifie la forme exacte du dictionnaire ne fonctionne plus.
- **Contraintes de Python 3.9.6.** Pas de `@dataclass(slots=True)` (3.10+), pas de `kw_only=True` (3.10+), et les annotations PEP 604 `int | None` échouent lors de l’exécution sans `from __future__ import annotations`. Si la priorité est modélisée sous forme d’énumération, `enum.StrEnum` est disponible à partir de la version 3.11 et n’est donc pas accessible. N’importe lequel de ces cas entraînerait une défaillance du fixture sur cet interpréteur.
- **L’attribution des identifiants se situe au mauvais niveau.** `SchedulerService._next_identifier` signifie que le service gère la génération des identifiants tandis que le référentiel gère le stockage. Si le travail sur les priorités conduit à la mise en place d’un deuxième référentiel ou de fixtures préchargées, cette séparation entraînera des collisions d’identifiants et l’écrasement de tâches.
- **Contrats d’erreur asymétriques.** `JobRepository.get` renvoie `None` en cas d’échec, tandis que `JobRepository.delete` lève une `KeyError`. Toute nouvelle recherche liée à la priorité devrait adopter délibérément une convention plutôt que d’hériter accidentellement de cette incohérence.
- **Précédent de lacune de validation.** `create_job` valide `name` mais pas `owner`. Ne reproduisez pas ce laxisme pour `priority` : une priorité non validée se propage dans la clé de tri et peut lever une exception `TypeError` au cœur de `sorted` (par exemple, en comparant un `int` à `None`) plutôt qu’au niveau du site d’appel.
- **Piège du code mort.** `scheduler/time_rules.py` ressemble à une logique de planification et attirera des modifications. Il n’est importé par aucun fichier, et sa propre chaîne de documentation admet le bug : il ajoute 24 heures écoulées en UTC et " décale l’heure locale réelle lors des changements d’heure d’été ". Le modifier n’a aucun effet observable sur le système testé ; l’effort consacré à cette tâche est donc vain et aucun test écrit à son sujet ne valide quoi que ce soit de ce qui sera livré.
- **Filet de sécurité fragile.** Deux tests, pas de CI, pas de linter, pas de vérification de types. Rien ne permet de détecter une régression, sauf ce que vous écrivez vous-même. Considérez la suite de tests existante comme une couverture de base insuffisante, et non comme un filtre.
### 6. Plan de mise en œuvre (non exécuté)
1. **Définir d’abord la sémantique, par écrit.** Type de priorité (`int` ou énumération), plage valide, valeur par défaut pour les tâches existantes/non spécifiées, et sens de tri. Consignez-les sous forme de chaîne de documentation (`docstring`) sur `Job` dans `scheduler/models.py` — c’est le seul endroit dont toutes les couches dépendent déjà.
2. **Étendre le modèle.** Ajouter `priority: int = 0` en tant que *dernier* champ de `Job` dans `scheduler/models.py`, en préservant la compatibilité positionnelle avec `service.py:13` et en laissant `to_dict()` inchangé.
3. **Intégrez-le dans le service.** Ajoutez un paramètre `priority` par défaut à `SchedulerService.create_job`, validez-le à côté de la condition existante `name.strip()` (en levant une exception `ValueError`, correspondant au type d’erreur établi), puis transmettez-le au constructeur `Job`.
4. **Définir explicitement le contrat de liste.** Option privilégiée à faible risque : laisser `JobRepository.all()` tel quel en tant que primitive triée par identifiant, et ajouter un accesseur distinct trié par priorité. Si, au contraire, la signification de `list_jobs()` doit changer, modifiez la compréhension de `JobRepository.all()` pour trier les valeurs selon une clé composée explicite incluant `identifier` comme critère de départage, et notez cette modification dans `README.md`.
5. **Maintenez `scheduler/__init__.py` à jour** uniquement si une énumération ou une constante publique a été introduite.
6. **Ne modifiez pas `scheduler/time_rules.py`**, et n’ajoutez pas de fichiers à moins que la propriété `expected_files` du fichier `fixture-manifest.json` ne soit mise à jour dans le cadre de la même modification.
### 7. Plan de validation
- **Commencez par la base de référence.** Exécutez `python3 -m unittest discover -s tests -v` avant toute modification et vérifiez que les deux tests sont réussis. Je l’ai déjà fait — tout passe sans problème.
- **Contrôle de régression.** Les deux tests existants doivent toujours réussir sans modification. Si `test_create_and_list_jobs` nécessite une modification, cela indique que la modification introduit un bug, et non une raison de modifier le test.
- **Nouveaux cas dans `tests/test_scheduler.py` :**
- Priorité par défaut lorsque `create_job` est appelé avec l’ancienne signature à deux arguments (pour prouver la compatibilité ascendante).
- Allers-retours explicites de priorité via `create_job` → `list_jobs`.
- Tri avec **trois priorités distinctes ou plus**, vérifiant la liste complète — c’est ce qui détermine le sens du tri.
- Égalité : deux tâches de priorité égale sont classées par ordre croissant d’identifiant.
- Une priorité non valide lève une exception `ValueError`, à l’instar du cas d’un nom vide.
- `to_dict()` inclut `priority` avec la valeur attendue.
- Chemin de dépôt injecté : `SchedulerService(repository=fake)` attribue toujours correctement la priorité, en testant la jonction `repository or JobRepository()`.
- **Vérification de compatibilité.** Vérifier que tout fonctionne spécifiquement sous Python 3.9.6 — pas de `slots=`, pas de `kw_only=`, pas d’unions PEP 604 nues, pas de `StrEnum`.
- **Vérification de l’inventaire.** Relisez `fixture-manifest.json` et vérifiez que l’ensemble des fichiers sur le disque correspond toujours à `expected_files`.
- **Déterminisme.** Exécutez la suite de tests deux ou trois fois ; des bogues de tri liés à l’ordre d’itération des dictionnaires peuvent se manifester de manière intermittente.
- **Propreté.** Exécutez avec `PYTHONDONTWRITEBYTECODE=1` afin que les répertoires `__pycache__` n’apparaissent pas comme des écarts non suivis par rapport au manifeste.
Limitation liée à l'environnement de test : il s'agissait d'un petit référentiel Python hors ligne. Claude utilisait un sous-agent de secours après l'expiration de l'OAuth via l'interface en ligne de commande (CLI) ; par conséquent, l'isolation et la visibilité des jetons n'étaient pas identiques.
Ce résultat ne permet pas d'évaluer les performances sur un monorepo de grande envergure ni lors d'une session autonome d'une semaine. Le scénario a été délibérément conçu pour être de petite envergure et contrôlé. Pour une évaluation réelle, commencez par une invite en lecture seule : demandez à chaque outil de cartographier le chemin d'appel, de nommer les fichiers qu'il modifierait, d'identifier les tests et de répertorier les hypothèses non résolues avant d'autoriser les modifications.
Mode de mise en œuvre, portée du correctif et correction des bogues
Travail sur plusieurs fichiers
Un même comportement de réussite peut résulter de choix techniques différents. Dans le cadre du test T2, les deux produits ont obtenu un score de 30/30 et ont réussi le test de validation « frozen hidden ». Le code Claude a intégré des validations à plusieurs points de délimitation et a ajouté des tests plus complets portant sur le modèle direct et les seuils. Codex a utilisé une implémentation plus légère, centrée sur les services, qui respectait également le contrat.
Pour un développeur indépendant, il s’agit là d’un véritable compromis. Une validation plus large permet de protéger les invariants lorsque les objets sont créés via plusieurs chemins. Un correctif plus restreint peut réduire la surface de régression et le temps de révision lorsqu’un seul service est le point d’entrée prévu. La bonne réponse dépend des règles de propriété du référentiel, et non du simple décompte des lignes modifiées ou des tests pris isolément.
T2 · Test du référentiel contrôlé
Mettre en œuvre une fonctionnalité prioritaire dans plusieurs fichiers
Ajouter le comportement « frozen », préserver la compatibilité et passer les tests publics et cachés.
J'ai ajouté une priorité au modèle immuable, je l'ai validé au niveau de la limite du service et j'ai conservé l'ordre dans le référentiel. Les sept tests publics et le validateur caché figé ont tous réussi.
Avis du critique : Une implémentation plus concise, axée sur les services, qui prenait en charge tous les comportements figés.
Validation de la priorité tant au niveau de la limite du service qu’au niveau du modèle immuable, préservation du filtrage du référentiel et ajout d’une couverture des seuils. Quatorze tests publics et le validateur caché ont été réussis.
Avis du critique : Une couverture plus large du modèle direct et du seuil, sans avantage en termes de score fonctionnel.
Afficher l'intégralité des résultats de Codex
Sortie complète, validée et aseptisée
Mise en place de la fonctionnalité de priorité des tâches planifiées. Fichiers modifiés : - [scheduler/models.py](./scheduler/models.py:5) — ajout d'une variable sérialisée `priority`, dont la valeur par défaut est `0`. - [scheduler/service.py](./scheduler/service.py:11) — Ajout de la validation, du stockage et du filtrage `list_jobs(min_priority=0)` tout en conservant l'ordre des identifiants. - [tests/test_scheduler.py](./tests/test_scheduler.py:16) — ajout de la couverture pour les valeurs par défaut, la sérialisation, le stockage, les limites, les valeurs non valides et le filtrage. Tests exécutés : ```text python3 -m unittest discover -s tests -v 7 tests exécutés — OK ``` **Conclusion :** La tâche gelée est terminée et vérifiée. **Décision requise :** Aucune.
Afficher l'intégralité du code de sortie Claude
Compte rendu complet du transfert, y compris la transcription mot pour mot de la première sortie valide
Fichier d'exécution # T2 — Fonctionnalité de priorité multi-fichiers Paramètres d'exécution ## | Champ | Valeur | | --- | --- | | Tâche | `T2` | | Invite figée | `01-prompts/T2.md` | | SHA-256 de la invite gelée | `8476a56034c4e719b97ee4081b32b4c73efd45feafe1bda9d477c83cb8fdb698` | | Unité d’exécution | sous-agent Claude isolé, `usage général`, contexte vierge | | Méthode d’isolation | **repli sur sous-agent** (rétrogradation documentée — voir `results/isolation-decision.md`) | | Copie propre attribuée | `runtime/workspaces/T2` | | Version du code Claude | `2.1.220` | | Paramètres du modèle | `claude-opus-5` | | start_utc | `2026-07-28T10:27:52Z` | | end_utc | `2026-07-28T10:29:33Z` | | Durée | 101 s (en parallèle avec T1, T3, T4 ; mesure de latence non fiable) | | Numéro de tentative | 1 | | Statut | `valide` | | Intervention humaine | aucune | ## Résumé de l'outil de sécurité `date`, `Lecture`/`Modification`/`Écriture` uniquement dans l’espace de travail attribué, `grep`, `python3 -m unittest discover`, `python3 -m compileall`, vérifications de base `python3 -c` en ligne. Pas de réseau, pas d’installations, bibliothèque standard uniquement. ## Fichiers modifiés `scheduler/models.py`, `scheduler/repository.py`, `scheduler/service.py`, `tests/test_scheduler.py`. Aucun fichier n’a été ajouté ni supprimé, donc `fixture-manifest.json` reste exact. Patch complet : `results/T2/patch.diff`. ## Résultats des vérifications hors ligne Rapportés par l’exécuteur de tâches : | Vérification | Résultat | | --- | --- | | `python3 -m unittest discover -s tests -v` (référence, avant modification) | 2 réussis, 0 échoués | | `python3 -m compileall -q scheduler tests` | sans erreur | | tests de fumée intégrés (construction héritée à 3 arguments, seuil de mot-clé/positionnel, `to_dict`) | réussi | | `python3 -m unittest discover -s tests -v` (final) | **14 réussis, 0 échoués** | Revérifié de manière indépendante par le coordinateur depuis l’extérieur de l’espace de travail : | Vérification | Sortie | Résultat | | --- | --- | --- | | suite publique (`results/checks/T2-public.txt`) | 0 | 14 tests, OK | | validateur caché `03-checks/test_t2_hidden.py` (`results/checks/T2-hidden.txt`) | 0 | 2 tests, OK | Le validateur caché échoue (sortie 1) sur une copie vierge du fixture, ce qui confirme que la réussite est pertinente. Voir `results/checks/validator-controls.md`. ## Couverture des comportements de la carte de référence Les cinq comportements requis dans `03-checks/gold-map.json` sont tous satisfaits : | Comportement requis | Preuve | | --- | --- | | priorité par défaut 0 | `Job.priority: int = MIN_PRIORITY` ; `create_job(..., priority=MIN_PRIORITY)` ; `test_priority_defaults_to_zero` | | plage d’entiers de 0 à 9 | `validate_priority` rejette les valeurs non entières et hors plage ; `test_out_of_range_priority_is_rejected`, `test_non_integer_priority_is_rejected` | | priorité sérialisée | `to_dict()` via `asdict` ; `test_priority_appears_in_serialized_output` vérifie que le dictionnaire est exact | | filtrage par priorité minimale | `list_jobs(min_priority=0)` → `JobRepository.all(min_priority)` ; `test_filter_is_inclusive_of_the_threshold` | | tri des identifiants | filtre appliqué à l’intérieur de la compréhension existante `sorted(self._jobs)` ; `test_filter_preserves_ascending_identifier_order` | ## Erreurs corrigées Aucune. Les artefacts `__pycache__` issus des exécutions de tests ont été supprimés par le gestionnaire de tâches ; un balayage du coordinateur a confirmé que l'espace de travail est propre. ## Sortie visible (mot pour mot) Ajout d’un champ entier `priority` aux tâches planifiées dans les couches modèle, référentiel et service du dispositif de planification local, ainsi qu’à la liste filtrée. **`scheduler/models.py`** — Ajout des constantes de module `MIN_PRIORITY = 0` / `MAX_PRIORITY = 9` et d’une fonction réutilisable `validate_priority(priority)` qui lève une exception `ValueError` pour les valeurs non entières et pour celles situées en dehors de la plage comprise entre 0 et 9 inclus. Le type `bool` est explicitement rejeté bien qu’il s’agisse d’une sous-classe de `int` ; ainsi, `True` ne peut pas passer pour une priorité 1. La classe de données figée `Job` se voit ajouter `priority: int = MIN_PRIORITY` en tant que champ final avec une valeur par défaut, ce qui permet de conserver le fonctionnement de la construction à 3 arguments existante, ainsi qu’une méthode `__post_init__` qui appelle le validateur afin qu’aucune priorité invalide ne puisse être construite, quel que soit le chemin. `to_dict()` a été conservé sous la forme `asdict(self)`, de sorte que la priorité apparaît automatiquement dans la sortie sérialisée, dans l’ordre des champs. **`scheduler/repository.py`** — `JobRepository.all()` accepte un argument facultatif `min_priority` et effectue le filtrage au sein de la compréhension existante `sorted(self._jobs)`, ce qui garantit un ordre croissant des identifiants via le même chemin de code unique qui le fournissait déjà, plutôt que de le rétablir après le filtrage. L’argument par défaut préserve le comportement précédent (sans argument) pour les appelants existants. Le stockage lui-même n’a nécessité aucune modification : le référentiel stocke des instances `Job` complètes, de sorte que la priorité est conservée et transmise lors des allers-retours via `save`/`get`/`all`. **`scheduler/service.py`** — `create_job` accepte un argument `priority` facultatif en fin de liste (valeur par défaut : 0) et le valide avant de construire l’objet `Job` ; ainsi, l’exception est levée à la limite du service avec le même contrat `ValueError` que la vérification existante du nom vide. `list_jobs(min_priority=0)` délègue la tâche au référentiel. Le tri et le filtrage sont regroupés en un seul endroit plutôt que d’être dupliqués. **Remarque de conception concernant la validation de `min_priority` :** sa valeur est vérifiée comme étant un entier, mais elle n’est délibérément *pas* limitée à la plage 0–9. La règle 0–9 impose des contraintes sur ce qu’un job peut stocker ; un seuil est un paramètre de requête, et rejeter par exemple `min_priority=10` transformerait une requête légitime " ne correspondant à rien " en une erreur. Le fait que `list_jobs(min_priority=9)` renvoie `[]` lorsqu’aucune tâche n’a la priorité 9 est couvert par un test. Le fichier `scheduler/time_rules.py` a été consulté mais n’a pas été modifié — le décalage lié à l’heure d’été qui y est documenté correspond à un comportement préexistant, hors du champ d’application de cette tâche, et le modifier aurait entraîné un changement de comportement sans rapport avec celle-ci. Aucun fichier n’a été ajouté ni supprimé ; le fichier `fixture-manifest.json` reste donc exact (vérifié par programmation). ### Couverture de test ajoutée Valeur par défaut de 0 ; aller-retour en mémoire via `JobRepository` ; priorité dans la sortie de `to_dict()` ; valeurs limites 0 et 9 acceptées ; valeurs hors plage −1/10/100 rejetées ; valeurs non entières `"3"`/`3.5`/`None`/`True` rejetées ; validation directe au niveau du modèle ; ordre de liste non filtré ; liste filtrée conservant l’ordre croissant des identifiants ; seuil inclusif ; résultat vide ; valeur non entière de `min_priority` rejetée.
Limitation liée à l'environnement de test : il s'agissait d'un petit référentiel Python hors ligne. Claude utilisait un sous-agent de secours après l'expiration de l'OAuth via l'interface en ligne de commande (CLI) ; par conséquent, l'isolation et la visibilité des jetons n'étaient pas identiques.
Correction de bogues dans des cas limites
T3 a testé un défaut de planification lié à l'heure d'été. Les deux agents ont obtenu un score de 30/30 et ont réussi les mêmes contrôles cachés au printemps et à l'automne. Le code Claude a ajouté une couverture explicite pour les heures locales ambiguës ou ignorées, les entrées naïves et les cycles de plusieurs jours. Codex a apporté une modification plus restreinte au calendrier et a satisfait au contrat figé.
Des tests plus complets couvrant les cas limites renforcent la confiance lorsque la bibliothèque est largement réutilisée ou que le coût d’une erreur d’ordonnancement est élevé. Une modification ciblée est préférable lorsque le défaut est bien isolé et que l’équipe souhaite minimiser les changements de comportement. La question pratique à se poser n’est pas “ Qui a écrit le plus de code ? ”, mais de savoir si le correctif résout la cause première identifiée, préserve les contrats environnants et vérifie les limites à risque.
T3 · Test du référentiel contrôlé
Corriger la planification quotidienne lors des changements d'heure d'été
Conserver l'heure de New York demandée pendant les périodes de transition entre le printemps et l'automne.
Cause première : la mise en œuvre a ajouté 24 heures UTC écoulées. Solution : avancer d'un jour civil local. Les contrôles « spring » et « fall » figés ont tous deux réussi.
Avis du critique : La partie la plus restreinte a adopté l'ensemble du contrat gelé.
Prise en compte du printemps et de l'automne, des heures locales manquantes ou ambiguës, des données brutes et des cycles de plusieurs jours. Les deux contrôles cachés « gelés » ont été validés après une couverture de régression élargie.
Avis du critique : Une couverture plus large des cas limites ; le même score fonctionnel selon la grille d'évaluation figée.
Afficher l'intégralité des résultats de Codex
Sortie complète, validée et aseptisée
Correction du problème lié à l'heure d'été mise en œuvre. Fichiers modifiés : - [scheduler/time_rules.py](./scheduler/time_rules.py) - [tests/test_time_rules.py](./tests/test_time_rules.py) Modifications : - Avance d'un jour civil local au lieu de 24 heures UTC. - Ajout de tests de régression pour le passage à l'heure d'été et le retour à l'heure d'hiver à New York. - Vérification que les intervalles UTC écoulés sont respectivement de 23 et 25 heures. Vérifications : - Tests unitaires : 4 réussis. - Vérification syntaxique en mémoire : 7 fichiers Python ont réussi. - La compilation du bytecode a été bloquée car Python redirige son cache en dehors de l’espace de travail attribué ; aucun fichier externe n’a été écrit. **Conclusion :** `next_daily_run` conserve désormais l’heure réelle demandée lors des transitions d’heure d’été. Aucune décision n’est requise.
Afficher l'intégralité du code de sortie Claude
Compte rendu complet du transfert, y compris la transcription mot pour mot de la première sortie valide
Fichier d'exécution # T3 — Correction d'un bug DST
Paramètres d'exécution ##
| Champ | Valeur |
| --- | --- |
| Tâche | `T3` |
| Invite figée | `01-prompts/T3.md` |
| SHA-256 de la invite gelée | `3fee50d0230f27f8d6dd7f12e050fa3f0b7f5fb77d9559361fee96e5f1a47307` |
| Unité d’exécution | sous-agent Claude isolé, `usage général`, contexte neuf |
| Méthode d’isolation | **repli sur sous-agent** (rétrogradation documentée — voir `results/isolation-decision.md`) |
| Copie propre attribuée | `runtime/workspaces/T3` |
| Version du code Claude | `2.1.220` |
| Paramétrage du modèle | `claude-opus-5` |
| start_utc | `2026-07-28T10:28:05Z` |
| end_utc | `2026-07-28T10:30:03Z` |
| Durée | 118 s (en parallèle avec T1, T2, T4 ; mesure de latence non pure) |
| Numéro de tentative | 1 |
| Statut | `valide` |
| Intervention humaine | aucune |
## Résumé de l’outil Safe
`date`, `Lecture`/`Modification` uniquement dans l’espace de travail attribué, `python3 -m unittest discover`,
`python3 -m compileall`, une exécution de contrôle négatif en mémoire, une vérification de l’intégrité du manifeste.
Bibliothèque standard uniquement (`datetime`, `zoneinfo`, `unittest`). Pas de réseau, pas d’installations.
## Fichiers modifiés
`scheduler/time_rules.py` (la correction — uniquement le corps et la chaîne de documentation de `next_daily_run`),
`tests/test_scheduler.py` (ajout de `NextDailyRunTests`, 8 tests, plus une fonction d'aide `_elapsed` ;
les tests existants n’ont pas été modifiés). Aucun autre module n’a été modifié, aucun fichier n’a été ajouté. Patch complet :
`results/T3/patch.diff`.
## Résultats de la vérification hors ligne
Rapportés par l’exécuteur de tâches :
| Vérification | Résultat |
| --- | --- |
| `python3 -m unittest discover -s tests -v` | **10 réussis, 0 échoués** (2 préexistants + 8 nouveaux) |
| `python3 -m compileall -q scheduler tests` | sans erreur |
| Intégrité du manifeste par rapport à `fixture-manifest.json` | 0 élément manquant, 0 élément inattendu |
| Contrôle négatif : implémentation de référence patchée en mémoire, `NextDailyRunTests` uniquement | 8 tests exécutés, **5 échecs comme prévu**, y compris les deux tests DST |
Revérifié de manière indépendante par le coordinateur depuis l’extérieur de l’espace de travail :
| Vérification | Sortie | Résultat |
| --- | --- | --- |
| suite publique (`results/checks/T3-public.txt`) | 0 | 10 tests, OK |
| validateur caché `03-checks/test_t3_hidden.py` (`results/checks/T3-hidden.txt`) | 0 | 2 tests, OK |
Le validateur caché échoue (sortie 1) sur une copie vierge du fixture. Voir
`results/checks/validator-controls.md`.
## Couverture des comportements de la carte de référence
Les quatre comportements requis dans `03-checks/gold-map.json` sont tous satisfaits :
| Comportement requis | Preuve |
| --- | --- |
| Heure de l’horloge murale conservée | incrément appliqué à l’horloge murale locale naïve, fuseau horaire réattribué ; vérifié dans chaque test d’heure d’été |
| Transition de printemps couverte | `test_spring_forward_keeps_requested_hour` — heure 09h30 conservée, décalage `-04:00`, durée écoulée : 23 h |
| Transition d’automne couverte | `test_fall_back_keeps_requested_hour` — heure 09h30 conservée, décalage `-05:00`, durée écoulée : 25 h |
| Fuseau horaire IANA utilisé | `ZoneInfo("America/New_York")` issu de la bibliothèque standard |
Au-delà de l’ensemble requis, le testeur a également couvert les deux cas limites de la PEP 495 — un temps réel
ignoré lors du passage à l’heure d’été et un temps réel ambigu lors du retour à l’heure d’hiver — ainsi que des cycles de sept jours
chevauchant chaque transition et un comportement en cas d’entrée naïve.
## Erreurs corrigées
Deux échecs d’assertions de test dus à une erreur de notre part : `following - previous` sur deux dates-heures partageant un
`tzinfo` soustrait les heures réelles naïves, ce qui a conduit les assertions de temps écoulé à afficher 1 jour et à échouer.
L’implémentation était correcte et les assertions étaient erronées ; correction effectuée à l’aide d’une fonction auxiliaire `_elapsed`
qui convertit d’abord les deux opérandes en UTC. Aucune erreur d’outils, d’importation ou d’environnement.
Les artefacts `__pycache__` ont été supprimés après l’exécution.
## Sortie visible (textuel)
**Reproduction**
`scheduler/time_rules.py::next_daily_run` a été appelé avec une date-heure `America/New_York` de part et d’autre d’un changement d’heure d’été en 2024 :
```
2024-03-09T09:30:00-05:00 -> 2024-03-10T10:30:00-04:00 # : décalage horaire de +1
2024-11-02T09:30:00-04:00 -> 2024-11-03T08:30:00-05:00 # : décalage horaire de -1
```
Une tâche prévue à 09h30 heure locale a été lancée à 10h30 après le passage à l’heure d’été et à 08h30 après le retour à l’heure d’hiver.
**Cause première**
L’implémentation d’origine traitait " daily " comme une durée absolue fixe :
```python
elapsed = previous_run.astimezone(timezone.utc) + timedelta(hours=24)
return elapsed.astimezone(previous_run.tzinfo)
```
La conversion préalable en UTC fait que `timedelta(hours=24)` correspond exactement à 24 heures écoulées. Or, un jour calendaire local dans un fuseau horaire IANA dure 23 h le jour du passage à l’heure d’été et 25 h le jour du retour à l’heure d’hiver ; un décalage constant de 24 h se retrouve donc nécessairement à une heure de l’heure réelle demandée.
**La correction** (`scheduler/time_rules.py`)
La récurrence quotidienne est une règle de calendrier ; l’incrément est donc désormais appliqué à l’heure locale brute, le fuseau horaire étant réattribué par la suite :
```python
tzinfo = previous_run.tzinfo
naive_next = previous_run.replace(tzinfo=None) + timedelta(days=1)
if tzinfo is None:
return naive_next
candidate = naive_next.replace(tzinfo=tzinfo, fold=0)
return candidate.astimezone(timezone.utc).astimezone(tzinfo)
```
Pourquoi cela est correct :
- Le calcul de l’horloge murale sur la valeur « naïve » est indépendant du décalage horaire ; ainsi, l’heure et la minute demandées sont conservées par construction ; `zoneinfo` fournit ensuite le décalage UTC en vigueur à la nouvelle date (vérifié : `-04:00` après le passage à l’heure d’été, `-05:00` après le retour à l’heure d’hiver, temps réel écoulé respectivement de 23 h et 25 h).
- `fold=0`, combiné au cycle aller-retour UTC, gère les deux cas limites que l’arithmétique pure de l’horloge murale laisse mal définis. Conformément à la PEP 495, une heure murale *sautée* (02 h 30 le 10/03/2024) a le décalage d’avant la transition à `fold=0` ; le va-et-vient le normalise donc à l’instant réel 03 h 30 EDT plutôt que de renvoyer une date-heure ne désignant aucun instant. Une heure réelle *ambiguë* (01 h 30 le 03/11/2024) est résolue de manière déterministe vers sa première occurrence (EDT) au lieu d’être arbitraire.
- Une entrée « naïve » conserve sa signification antérieure (simplement +1 jour calendaire) — aucune nouvelle exigence `tzinfo` n’est imposée aux appelants.
La portée a été maintenue étroite : seuls le corps et la chaîne de documentation de `next_daily_run` ont été modifiés. `service.py`, `models.py`, `repository.py` et `__init__.py` n’ont pas été modifiés, aucun nouveau fichier n’a été ajouté et le manifeste des fixtures correspond toujours exactement (aucun fichier manquant ou inattendu). Utilisation exclusive de la bibliothèque standard (`datetime`, `zoneinfo`, `unittest`).
**Tests de régression** (`tests/test_scheduler.py`, nouveau `NextDailyRunTests`, 8 tests) couvrent : la stabilité en temps normal, le passage à l’heure d’été + décalage + 23 h écoulées, le passage à l’heure d’hiver + décalage + 25 h écoulées, des cycles de sept jours chevauchant chaque transition, un temps réel sautée, un temps réel ambigu et une entrée naïve.
Deux remarques méritent d’être notées. Premièrement, mes assertions initiales sur le temps écoulé utilisaient `following - previous` ; Python ignore un `tzinfo` partagé et soustrait les heures réelles naïves, ce qui a conduit les deux à renvoyer 1 jour et à échouer. L’implémentation était correcte et les assertions erronées — correction effectuée à l’aide d’une fonction auxiliaire `_elapsed` qui convertit les deux opérandes en UTC. Deuxièmement, j’ai vérifié que les tests détectaient bien le défaut d’origine en réexécutant `NextDailyRunTests` sur une copie en mémoire de l’implémentation initialisée : 5 tests sur 8 ont échoué, y compris les deux tests relatifs à l’heure d’été. Les trois tests qui réussissent avec la version boguée (jour ordinaire, saut, ambiguïté) documentent le comportement plutôt que de détecter une régression — les cas « saut » et « ambiguïté » coïncident par hasard, car un décalage absolu de +24 h tombe justement sur le même instant normalisé.
Limitation liée à l'environnement de test : il s'agissait d'un petit référentiel Python hors ligne. Claude utilisait un sous-agent de secours après l'expiration de l'OAuth via l'interface en ligne de commande (CLI) ; par conséquent, l'isolation et la visibilité des jetons n'étaient pas identiques.
Qualité de la révision du code et vérification humaine
Les tâches de révision de code font appel à des compétences différentes de celles requises pour la mise en œuvre de fonctionnalités. Un réviseur compétent doit identifier des problèmes reproductibles, évaluer leur impact, indiquer le chemin d'accès exact au code et distinguer un véritable défaut d'un avertissement hypothétique. La correction d'un problème implique un test supplémentaire : le correctif ne doit pas introduire de nouvelle régression.
Le code Claude présentait l'avantage le plus net dans la catégorie T4. Il a signalé cinq résultats reproductibles de manière indépendante, y compris les deux cibles d’audit préétablies, et a obtenu une note de 19/20. Codex a signalé et corrigé deux défauts valides de gravité élevée, mais n’a pas mentionné la paire préétablie, obtenant ainsi une note de 18/20. Les résultats de Codex n’étaient pas des faux positifs ; la différence observée tenait davantage à l’exhaustivité qu’à l’exactitude fondamentale.
T4 · Test du référentiel contrôlé
Identifier les défauts reproductibles et corriger les problèmes présentant le plus haut niveau de fiabilité
Examinez le test, reproduisez les défauts réels, appliquez les corrections autorisées et vérifiez que les tests de régression valident le comportement.
1. Élevé — Les tâches existantes pourraient être écrasées sans avertissement. 2. Moyen — Les exécutions quotidiennes ont connu des décalages lors des changements d'heure. Vérification : quatre tests réussis, aucun échec.
Avis du critique : Des résultats utiles concernant les problèmes de gravité élevée et des corrections ciblées, mais les deux objectifs de révision fixés n'ont pas été atteints.
D1 Dérive de l'heure d'été (DST) · Élevé D2 Acquisition naïve du fuseau horaire · Moyen D3 Collision d'identifiants · Élevé D4 L'absence de suppression provoque une erreur « KeyError » · Moyen D5 Propriétaire non validé · Faible
Avis du critique : Une couverture d'analyse plus étendue, sans aucun faux positif reproduit ; deux anomalies liées au contrat n'ont pas été corrigées.
Afficher l'intégralité des résultats de Codex
Sortie complète, validée et aseptisée
## Conclusions nécessitant une action 1. **Risque élevé — Les tâches existantes pourraient être écrasées sans avertissement** - Preuve : initialisation de l’identifiant dans [service.py](./scheduler/service.py:8), combinée au remplacement du dictionnaire dans [repository.py](./scheduler/repository.py:9). - Impact : la création d’un service à partir d’un référentiel existant pourrait réutiliser l’identifiant `1`, remplaçant ainsi la tâche stockée et entraînant une perte de données. - Reproduction minimale : enregistrer `Job(1, ...)`, construire `SchedulerService(repository)`, puis créer une autre tâche. Avant la correction, seule la nouvelle tâche subsistait. - Correction : initialiser l’identifiant suivant à partir de l’identifiant existant le plus élevé du référentiel. - Test de régression : [test_scheduler.py](./tests/test_scheduler.py:22). 2. **Impact moyen — Les exécutions quotidiennes ont subi des décalages lors des changements d’heure d’été** - Preuve : calcul corrigé dans [time_rules.py](./scheduler/time_rules.py:4). - Impact : une tâche quotidienne planifiée à 09h00 s’exécutait à 10h00 après le passage à l’heure d’été au printemps. - Reproduction minimale : calculer la prochaine exécution après `2026-03-07 09:00 America/New_York`. Avant la correction, le résultat était `2026-03-08 10h00`. - Correction : ajouter un jour civil local au lieu de 24 heures UTC écoulées. - Test de régression : [test_scheduler.py](./tests/test_scheduler.py:33). ## Fichiers modifiés - [scheduler/service.py](./scheduler/service.py) - [scheduler/time_rules.py](./scheduler/time_rules.py) - [tests/test_scheduler.py](./tests/test_scheduler.py) ## Vérification - Les deux tests de régression ont échoué avant leur correction. - Chacun a réussi après la correction correspondante. - `PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -v` - Résultat : **4 tests réussis, 0 échec**. - Il ne reste aucun artefact de cache Python généré. ## Conclusion et décision - **Conclusion :** Les deux défauts confirmés sont corrigés et couverts par des tests de régression ciblés. - **Décision requise :** Aucune.
Afficher l'intégralité du code de sortie Claude
Compte rendu complet du transfert, y compris la transcription mot pour mot de la première sortie valide
# T4 : Compte-rendu d'exécution — Test et révision du code
## Paramètres d'exécution
| Champ | Valeur |
| --- | --- |
| Tâche | `T4` |
| Invite figée | `01-prompts/T4.md` |
| SHA-256 de la prompt figée | `5e69546007ea776f40b3d334ddb75671ff684c151c77551bad27de3b0fdce640` |
| Unité d’exécution | sous-agent Claude isolé, `usage général`, contexte neuf |
| Méthode d’isolation | **repli sur sous-agent** (rétrogradation documentée — voir `results/isolation-decision.md`) |
| Copie propre attribuée | `runtime/workspaces/T4` |
| Version du code Claude | `2.1.220` |
| Paramétrage du modèle | `claude-opus-5` |
| start_utc | `2026-07-28T10:28:22Z` |
| end_utc | `2026-07-28T10:32:17Z` |
| Durée | 235 s (simultanée avec T1–T3 ; mesure de latence non précise) |
| Numéro de tentative | 1 |
| Statut | `valid` |
| Intervention humaine | aucune |
La condition figurant dans l’invite de commande gelée — " corrigez-les si la configuration d’exécution gelée autorise
les corrections " — a été résolue par le coordinateur à partir des fichiers `00-control/run-config.json` et
`00-control/safety-policy.json`, qui autorisent l’écriture de copies isolées des fixtures. Le runner a été
informé que les corrections étaient autorisées. Aucun fichier de contrôle ne lui a été présenté.
## Résumé des outils sécurisés
`date`, `Lecture`/`Modification`/`Écriture` uniquement dans l’espace de travail attribué, `grep`,
`python3 -m unittest discover`, `python3 -m compileall`, une exécution sur une copie temporaire vide, une
vérification de la présence du manifeste. Pas de réseau, pas d’installations, bibliothèque standard uniquement.
## Fichiers modifiés
`scheduler/time_rules.py` (modifié), `scheduler/service.py` (modifié),
`tests/test_scheduler.py` (modifié, +2 tests), `tests/test_time_rules.py` (ajouté, 5 tests).
Patch complet : `results/T4/patch.diff`.
## Résultats de la vérification hors ligne
Signalés par le gestionnaire de tâches :
| Vérification | Résultat |
| --- | --- |
| `python3 -m unittest discover -s tests -v` | **9 réussis, 0 échoués, 0 ignorés** (référence 2) |
| `python3 -m compileall -q scheduler tests` | réussi |
| Vérification de la présence du manifeste par rapport à `expected_files` | les 8 fichiers sont présents |
| Exécution de vacuity sur les implémentations d’origine restaurées | 5 échecs, 4 réussis, comme prévu |
Revérifié de manière indépendante par le coordinateur depuis l’extérieur de l’espace de travail :
| Vérification | Sortie | Résultat |
| --- | --- | --- |
| suite publique (`results/checks/T4-public.txt`) | 0 | 9 tests, OK |
Contrôle croisé à titre informatif, non noté : le validateur caché T3 réussit également sur cet
espace de travail (sortie 0), car T4 a corrigé de manière indépendante le même défaut `next_daily_run`. Voir
`results/checks/validator-controls.md`.
## Couverture des défauts de la carte de référence
`03-checks/gold-map.json` implante deux défauts pour l’évaluation T4. Les deux ont été détectés :
| Défaut implanté | Détecté | Signalé comme |
| --- | --- | --- |
| propriétaire vide accepté | oui | **D5**, `scheduler/service.py:11,13`, gravité Faible, signalé et délibérément non corrigé |
| La suppression d’un identifiant manquant provoque une erreur `KeyError` | oui | **D4**, `scheduler/repository.py:19` → `service.py:22`, gravité moyenne, signalé et délibérément non corrigé |
Trois autres anomalies ont été signalées en plus de celles initialement introduites. Aucune n’est un faux positif :
- **D1** — Décalage de l’heure d’été dans `next_daily_run`. Il s’agit du troisième défaut répertorié dans
`03-checks/seeded-defects.md` (il est classé sous T3 et non sous T4, mais il s’agit bien d’un bug pré-intégré).
- **D2** — Une entrée naïve dans `next_daily_run` récupère silencieusement le fuseau horaire de l’hôte et renvoie une
date-heure adaptée. Réel et dépendant de l’hôte ; vérifié par le coordinateur par rapport au code source du test.
- **D3** — collision d’identificateurs entre un service et un référentiel injecté ou partagé, provoquant un
écrasement silencieux. Réel : `SchedulerService._next_identifier` commence toujours à 1 tandis que
`JobRepository.save` est une affectation de dictionnaire non protégée. T1 a identifié de manière indépendante la même
faille à partir du test initial.
Nombre de faux positifs : **0**. Le runner a également correctement signalé l’absence de problèmes de sécurité, notant que
le test ne présente aucune surface d’attaque liée au réseau, aux E/S, à la désérialisation, aux sous-processus ou aux identifiants.
## Écart digne d’être noté
L’invite figée demandait des tests et des corrections sur " les deux défauts présentant le plus haut niveau de confiance ". L"
exécuteur a sélectionné D1/D2 (une correction, même fonction) et D3, plutôt que les deux défauts implantés dans la carte de référence
D4 et D5. La raison invoquée est défendable : D4 et D5 reposent tous deux sur un contrat API
non spécifié, leur correction relèverait donc de la conjecture. Le crédit de détection n’est pas affecté : les deux défauts pré-intégrés
ont été détectés, avec indication du fichier, de la ligne, de la gravité, de l’impact et de la reproduction. Les corrections appliquées concernaient de véritables
défauts et sont validées par un contrôle de vacuité.
## Erreurs corrigées
Deux échecs de test auto-provoqués dus à une soustraction entre le temps réel et le temps absolu sur des dates-heures
partageant un `tzinfo` ; corrigés et revérifiés. Aucune erreur liée aux outils ou à l’environnement. Les artefacts `__pycache__`
ont été supprimés après l’exécution.
## Sortie visible (mot pour mot)
### Rapport de défaut
**D1 — `scheduler/time_rules.py:10-11` — Le planning quotidien présente un décalage d’une heure lors du passage à l’heure d’été — Gravité : Élevée**
`next_daily_run` ajoute 24 heures *écoulées* via un aller-retour UTC au lieu de faire avancer le jour calendaire. Une tâche quotidienne étant définie par l’heure réelle, chaque tâche dans un fuseau horaire appliquant l’heure d’été se déclenche silencieusement avec une heure d’avance ou de retard à partir du jour du changement d’heure, et l’erreur persiste (chaque exécution se réinitialise à partir de l’heure décalée). La chaîne de documentation elle-même reconnaissait ce comportement.
```
prev = datetime(2024, 3, 9, 9, 0, tzinfo=ZoneInfo("America/New_York"))
next_daily_run(prev) # -> 10/03/2024 10:00:00-04:00, attendu 09:00-04:00
prev = datetime(2024, 11, 2, 9, 0, tzinfo=ZoneInfo("America/New_York'))
next_daily_run(prev) # -> 03/11/2024 08:00:00-05:00, prévu à 09:00-05:00
```
**D2 — `scheduler/time_rules.py:10-11` — Une entrée naïve récupère silencieusement le fuseau horaire local de la machine — Gravité : Moyenne**
Les deux mêmes lignes. `.astimezone(timezone.utc)` sur un objet `datetime` naïf suppose l'heure locale du système, et `.astimezone(None)` renvoie un objet `datetime` conscient du fuseau horaire. Un appel avec une valeur ' naïve " en entrée renvoie une valeur " consciente " en sortie ; le résultat n’est donc pas comparable aux autres valeurs " naïves " de l’appelant (`TypeError` lors de la comparaison) et la réponse dépend du paramètre `TZ` de l’hôte.
```
next_daily_run(datetime(2024, 1, 1, 9, 0))
# -> datetime(2024, 1, 2, 9, 0, tzinfo=timezone(timedelta(hours=8), "CST")) # dépendant de l’hôte
```
**D3 — `scheduler/service.py:8,13,15` (préfixe) — Une collision d’identifiants détruit silencieusement les tâches stockées — Gravité : Élevée**
Le compteur d’identifiants était propre à chaque `SchedulerService` et commençait toujours à 1, sans tenir compte du contenu du référentiel injecté. Tout deuxième service utilisant un référentiel partagé, ou tout service utilisant un référentiel prérempli, réattribuait l’identifiant 1 ; `JobRepository.save` étant une affectation de dictionnaire, la tâche existante était écrasée sans générer d’erreur. Perte de données.
```
repo = JobRepository()
SchedulerService(repo).create_job("Sauvegarde nocturne', 'Alex') # id 1
SchedulerService(repo).create_job('Exportation des fiches de paie", "Blake") # id 1 à nouveau
repo.all() # -> [Job(1, "Exportation des fiches de paie', 'Blake')] — La tâche d’Alex a disparu
```
**D4 — `scheduler/repository.py:19` → `scheduler/service.py:22` — `delete_job` lève une exception `KeyError` pour un identifiant inconnu — Gravité : Moyenne**
`delete` utilise `dict.pop` sans valeur par défaut, tandis que la méthode sœur `get` (ligne 13) renvoie `None` en cas d’absence de valeur. Cette incohérence provoque une exception `KeyError` brute via `SchedulerService.delete_job`, que les appelants ont peu de chances d’intercepter. Reproduction : `SchedulerService().delete_job(999)` → `KeyError: 999`. La correction consisterait à utiliser `pop(identifier, None)` ou à lever explicitement une exception de domaine — problème délibérément laissé tel quel, car le choix du comportement correct (opération silencieuse sans effet vs. erreur typée) relève d’une décision relative à l’API qui incombe au propriétaire.
**D5 — `scheduler/service.py:11,13` — Le champ ' owner ' n’est pas validé — Gravité : Faible**
La valeur de `name` est vérifiée pour s'assurer qu'elle n'est pas vide, mais pas celle de `owner` : `create_job('ok", " ")` stocke `owner=''`. Les deux paramètres appellent également `.strip()` sans protection, de sorte que `None` se traduit par `AttributeError : l’objet 'NoneType' n’a pas d’attribut 'strip'` plutôt que par la `ValueError` que l’API utilise habituellement en cas d’entrée incorrecte. Laissée telle quelle — le contrat prévu pour `owner` n’est mentionné nulle part dans le fixture.
**Sécurité :** aucune anomalie détectée. Le fixture ne présente aucune surface d’exposition au niveau du réseau, des E/S, de la désérialisation, des sous-processus ou des identifiants ; le stockage est un dictionnaire interne au processus.
**Lacune de couverture :** les fichiers `scheduler/time_rules.py` et `scheduler/repository.py` présentaient une couverture de test nulle avant cette exécution ; les deux tests initialisés ne couvraient que le scénario normal du service.
### Tests et corrections appliqués
Les deux défauts présentant le plus haut niveau de confiance étaient **D1/D2** (même fonction, une seule correction) et **D3**.
**Correction 1 — `scheduler/time_rules.py` :** remplacement du calcul aller-retour UTC par `previous_run + timedelta(days=1)`. Python effectue des calculs en temps réel sur les dates-heures « aware », et `zoneinfo` recalcule le décalage UTC de manière différée à partir de la nouvelle heure réelle — ainsi, 09:00 reste 09:00 tandis que le décalage évolue correctement de `-05:00 → -04:00`. Cela corrige à la fois D1 et D2 : les entrées « naïves » restent désormais « naïves » et le fuseau horaire local n’est jamais déduit. Le cas de transition horaire entre « inaccessible » et « ambigu » est documenté comme se référant aux règles de repli de `tzinfo`.
**Correction 2 — `scheduler/service.py` :** suppression du compteur `_next_identifier` par instance ; les identifiants sont désormais attribués à partir de l’état du référentiel selon la formule `max(identifiants existants, par défaut = 0) + 1` au moment de la création. Cela fonctionne correctement aussi bien pour les référentiels partagés que pour ceux préremplis. Compromis : O(n) par création au lieu de O(1), ce qui est acceptable pour un magasin en mémoire basé sur un dictionnaire, et garantit l’exactitude par rapport à un compteur qui ne peut pas voir le magasin dans lequel il écrit.
**Tests — `tests/test_time_rules.py` (nouveau, 5 tests) :** préservation de l’heure réelle lors du passage à l’heure d’été et au retour à l’heure d’hiver, temps écoulé absolu de 23 h/25 h lors de ces transitions, recalcul du décalage UTC, « naive-stays-naive » et avancement d’un jour en UTC simple. Saute proprement si aucune base de données IANA n’est présente.
**Tests — `tests/test_scheduler.py` (étendu, +2 tests) :** deux services partageant un même référentiel doivent émettre des identifiants distincts et conserver les deux tâches ; un service utilisant un référentiel prérempli avec les identifiants 1 et 7 doit émettre l’identifiant 8 et laisser les tâches existantes intactes.
**Vérification de vacuité :** j’ai restauré les deux implémentations d’origine dans une copie temporaire et relancé la suite de tests — les 5 nouveaux tests ont tous échoué (`FAILED (failures=5)`), et tous ont réussi avec le code corrigé. Les tests identifient bien les défauts.
Une correction a été apportée pendant l’exécution : dans ma première ébauche, j’avais vérifié le temps écoulé en heure d’été (DST) en utilisant `result - previous`, ce que Python évalue comme une opération arithmétique en temps réel lorsque les deux opérandes partagent un tzinfo ; cela donnait donc `24h` et les tests échouaient. Les assertions convertissent désormais les valeurs en UTC avant la soustraction. L’échec provenait de mon test, et non de la correction.
### Notes à l’attention du responsable
Le fichier `fixture-manifest.json` n’a pas été modifié ; `tests/test_time_rules.py` est donc un nouveau fichier valide qui ne figure pas dans `expected_files` — mettez à jour le manifeste si une vérification impose un ensemble de fichiers précis. Par ailleurs, les problèmes D4 et D5 ont été signalés mais n’ont délibérément pas été corrigés : ils dépendent tous deux d’une décision relative au contrat d’API (sémantique « miss-on-delete », règles de validation du propriétaire) qui n’est spécifiée nulle part dans le fixture ; choisir l’une des deux options aurait donc relevé de la conjecture plutôt que d’une véritable correction.
Limitation liée à l'environnement de test : il s'agissait d'un petit référentiel Python hors ligne. Claude utilisait un sous-agent de secours après l'expiration de l'OAuth via l'interface en ligne de commande (CLI) ; par conséquent, l'isolation et la visibilité des jetons n'étaient pas identiques.
Aucun de ces deux scores ne dispense d'un contrôle humain. Une fois la réparation effectuée par l'un ou l'autre des agents, vérifiez les interfaces modifiées, la portée inattendue des fichiers, l'absence de tests négatifs, l'historique des autorisations ou des commandes, ainsi que la procédure de restauration. Une explication convaincante ne remplace pas un test reproductible.
Autorisations, environnement isolé et sécurité opérationnelle
Un agent de codage peut lire du code privé, exécuter des commandes shell, modifier de nombreux fichiers et appeler des outils externes. La conception des autorisations fait donc partie intégrante de la qualité du produit. Les questions pertinentes sont les suivantes : quelles opérations nécessitent une autorisation, à quoi l’agent a-t-il accès par défaut, dans quelle mesure les actions à risque sont-elles clairement signalées, et un développeur peut-il vérifier les modifications qui en résultent ?.
Ne considérez pas systématiquement qu’un nombre réduit de demandes d’approbation est préférable. Une procédure simplifiée est utile dans un environnement isolé, sans identifiants ni connexions de production. Ce même comportement peut s’avérer dangereux dans un référentiel relié à des scripts de déploiement, à de véritables données clients ou à des autorisations cloud étendues. À l’inverse, un nombre excessif de demandes d’approbation peut rendre l’automatisation sécurisée peu pratique et inciter les utilisateurs à approuver des demandes sans les lire.
Notre test a été réalisé à partir de copies locales récentes, sans faire appel à des systèmes de production, sans déploiement et sans intervention humaine pendant l'exécution. Il évalue donc la réalisation des tâches dans des conditions sûres, et non la sécurité relative des deux produits. Avant d’utiliser l’un ou l’autre de ces outils pour des tâches importantes, commencez par un accès en lecture seule, définissez les répertoires et les commandes autorisés, examinez les différences et effectuez des vérifications objectives dans un environnement récupérable.
- Commencez par une architecture en lecture seule ou optez pour la solution de secours.
- N'approuvez que les commandes dont vous comprenez la portée et les conséquences.
- Veillez à ce que les identifiants, les données de production et les droits d'accès au déploiement ne soient pas inclus dans la version d'essai.
- Exigez un fichier de comparaison, des tests et une procédure de restauration claire avant d'accepter le résultat.
MCP, compétences, instructions relatives aux projets et personnalisation
Ces deux écosystèmes peuvent être étendus, mais les termes « extension » et « extension » ne doivent pas être considérés comme synonymes. Les instructions de projet indiquent à un agent comment se comporter au sein d’un référentiel. Les compétences réutilisables regroupent un workflow reproductible ou une expertise. MCP relie un hôte à des outils ou des données externes. Les hooks et les commandes permettent d’automatiser des étapes spécifiques d’un cycle de développement. Un produit peut exceller dans une couche sans pour autant correspondre point par point à une fonctionnalité d’une autre couche.
La question déterminante pour l'achat n'est pas de savoir s'il existe un logo d'intégration. Il s'agit plutôt de savoir si la connexion peut être installée, authentifiée, validée et exploitée sur l'hôte que vous utilisez réellement. Il faut également que le mode de défaillance soit compréhensible. Un serveur MCP qui fonctionne en mode interactif mais qui attend une validation lors d’une session sans surveillance reste utile, mais il ne devrait pas être qualifié d’automatisation « sans friction ».
Les instructions réutilisables présentent une mise en garde similaire. La longueur des fichiers d'instructions ne garantit pas le respect des règles, et un ensemble de règles trop complexe peut occulter le contexte ou créer des contradictions. Veillez à ce que les consignes du référentiel soient concises, vérifiables et étroitement liées au code. Précisez les commandes de vérification obligatoires, les zones protégées, les règles de style, ainsi que les cas dans lesquels l'agent doit s'arrêter pour demander confirmation.
- Instructions relatives au projet : règles spécifiques au référentiel et commandes de vérification.
- Compétences : procédures réutilisables ou modules d'expertise.
- MCP : connexions à des outils et des données externes.
- Hooks et commandes : automatisation autour d'événements définis du flux de travail.
Codex vs Claude : tarifs et limites d'utilisation
L'offre « Clean Consumer » est proposée à partir de $20 par mois. L'accès à Codex est inclus dans le forfait $20 ChatGPT correspondant, tandis que l'offre Claude Pro coûte $20 par mois aux États-Unis et inclut Claude Code. Les deux formules proposent des niveaux de forfait grand public pour une utilisation plus intensive, à $100 et $200. Des prix affichés similaires ne signifient pas pour autant des capacités identiques.
Le forfait “ Max 5x ” Claude coûte $100 par mois et le forfait “ Max 20x ” coûte $200 par mois. Les appellations « 5x » et « 20x » décrivent l’utilisation par session par rapport à la version Pro, et non un nombre garanti de tâches de codage. Les forfaits Claude et Claude Code partagent les mêmes limites de session et hebdomadaires. La longueur du contexte, les fichiers joints, le choix du modèle et l’utilisation des fonctionnalités peuvent influencer la vitesse à laquelle le quota est consommé.

Les crédits d'utilisation optionnels de Claude permettent, lorsqu'ils sont activés, de poursuivre les opérations éligibles au-delà du volume d'utilisation inclus ; ces crédits sont facturés séparément aux tarifs standard de l'API. L'authentification par clé API constitue un autre mode de facturation distinct. Qualifier l'un ou l'autre de ces modes d“” illimité » masquerait le coût marginal réel.

Codex distingue également l'utilisation incluse dans le forfait grand public, les crédits achetés éligibles et la facturation API. Les messages locaux et les discussions sur le cloud partagent un créneau de cinq heures, et des limites hebdomadaires peuvent également s'appliquer. Un champ « token » dans un journal CLI ne peut pas être converti directement en pourcentage sur cinq heures, en montant de crédit d'abonnement ou en facture API.
Pour une utilisation occasionnelle en solo, le niveau $20, quel que soit le côté, constitue un point de départ raisonnable. Un travail quotidien sur des référentiels impliquant des contextes longs peut justifier un niveau d’utilisation supérieur, mais uniquement après avoir observé les réinitialisations réelles et la consommation des tâches. Les travaux parallèles intensifs nécessitent encore plus de prudence : opter pour un niveau supérieur ne dispense pas de contrôler le contexte, de fractionner les tâches et de réserver les ressources de raisonnement coûteuses aux tâches nécessitant un haut niveau de jugement.
Résultats de notre test comparatif entre le Codex et le Code Claude
Nous avons figé quatre consignes en anglais, un ensemble de tests Python publics, des contrôles objectifs, une grille d’évaluation et une règle du « premier résultat valide » avant que l’un ou l’autre des agents ne soit lancé. Les tâches portaient sur la compréhension d’un dépôt inconnu, une fonctionnalité multi-fichiers, la correction d’un bug lié à l’heure d’été et la révision de code avec corrections. Les résultats valides n’ont fait l’objet d’aucune intervention humaine, et les résultats faibles mais valides ne pouvaient pas être réexécutés pour obtenir un meilleur score.
Codex a exécuté des processus CLI isolés avec du JSONL brut, en conservant les champs de jetons émis par l’interface CLI. La session OAuth CLI Claude de notre collègue ayant expiré, Claude Code a utilisé un coordinateur avec des contextes de sous-agents récents. Nous avons reconstitué les correctifs de Claude dans des copies d’audit vierges et avons réexécuté les vérifications publiques et cachées. Cela a permis d’obtenir des preuves pratiques crédibles, mais sans obtenir d’isolation ni de surfaces de contrôle de modèle identiques.
| Tâche | Codex | Claude Code | Interprétation bornée |
|---|---|---|---|
| T1 : Compréhension du référentiel | 20/20 | 20/20 | Égalité : approche compacte contre approche exhaustive |
| T2 : fonctionnalité de gestion de plusieurs fichiers | 30/30 | 30/30 | Lien fonctionnel ; portée différente de la validation et des tests |
| T3 : Réparation du DST | 30/30 | 30/30 | Les deux ont été approuvés : un patch plus étroit par rapport à une couverture plus large des bords |
| T4 : contrôle et réparation | 18/20 | 19/20 | Le code Claude a montré une plus grande étendue de l'examen |
Épreuve surveillée · Grille d'évaluation « Frozen »
Codex 98/100 contre Claude Code 99/100
Cet écart d'un point ne constitue pas un signal de réussite universel. Les différences pertinentes dépendent de la tâche à accomplir.
| Domaine de décision | Résultat observé | Lecture pratique |
|---|---|---|
| Compréhension du référentiel | Égalité · 20/20 chacun | Claude était plus complet ; Codex était plus concis. |
| Fonctionnalité de gestion de plusieurs fichiers | Égalité · 30/30 chacun | Les deux ont passé avec succès des contrôles discrets ; Claude a ajouté des tests plus approfondis. |
| Correction d'un bug lié à l'heure d'été | Égalité · 30/30 chacun | La version Claude couvrait davantage de bords ; Codex a utilisé le patch plus étroit. |
| Vérification et réparation | Claude 19/20 ; Codex 18/20 | La méthode Claude a permis de mettre en évidence davantage de défauts reproductibles. |
| Vitesse observée | Mixte | Claude a mené les T1/T2 ; Codex a mené les T3/T4. |
Mention légale : mêmes invites et même configuration, mais des chemins d'isolation différents. Ne généralisez pas ce petit test à tous les référentiels, niveaux de modèle ou sessions autonomes.
Ce test est trop limité pour permettre d'évaluer les performances sur de grands référentiels, tous les langages, tous les niveaux de modèles ou lors de longues sessions autonomes. L'écart total d'un point doit être interprété comme signifiant que “ les deux ont réussi, avec une différence quant à l'étendue de l'analyse ”, et non comme un classement universel.
Ce que rapportent les utilisateurs réels — et dans quelle mesure on peut s'y fier
Les retours de la communauté sont utiles lorsqu’ils portent sur un projet, une tâche, un modèle, un contexte d’utilisation et un horizon temporel. Ils sont en revanche peu pertinents lorsqu’un message se contente d’indiquer qu’un produit “ semble plus intelligent ” ou “ est beaucoup plus rapide ”. Les utilisateurs comparent en effet des référentiels, des niveaux d’abonnement, des invites, des extensions et des niveaux de supervision différents.
L'exemple contextuel tiré de Reddit ci-dessus suggère un compromis en matière d'interaction : une approche rapide et conversationnelle peut exiger davantage d'attention, tandis qu'une exécution réfléchie peut sembler plus lente mais nécessiter moins de corrections. Notre test contrôlé ne recoupe que partiellement ce témoignage. Il a révélé des vitesses variables et l’absence d’intervention humaine lors des exécutions valides ; il ne permet donc pas de valider l’affirmation selon laquelle une « surveillance » serait nécessaire. C’est précisément pour cette raison que les témoignages de la communauté et les résultats des tests contrôlés doivent être présentés conjointement, sans être confondus.
Le commentaire sur le « X harness » soulève un deuxième point intéressant : le résultat d'un codage appartient à l'ensemble du système, et pas seulement à l'étiquette du modèle. Aucun de ces deux messages ne doit être considéré comme une donnée d'enquête. Utilisez-les pour identifier les questions à se poser pour votre propre essai : nombre d'interventions, ampleur des différences, qualité des tests et capacité à se remettre d'une hypothèse erronée.
Extension des codes Codex et Claude avec le code GlobalGPT
GlobalGPT est un espace de travail multimodèle et multimodal, il ne remplace pas les agents de référentiel natifs. Son rôle concret est de compléter un hôte existant : utiliser un autre modèle d’agent disponible pour obtenir un deuxième avis, procéder à une révision des plans, valider la documentation ou générer des résultats spécialisés, tandis que Codex ou Claude Code reste responsable de l’accès au référentiel, des commandes shell, des tests et des validations.
GlobalGPT publie des guides officiels sur l'interface de ligne de commande (CLI) pour Codex et Claude Code, ainsi que Cursor. Lors de notre test d'intégration T5 en mode sécurisé, l'interface CLI a mené à bien la même tâche « gelée » dans les deux environnements comparés. Dans Codex, nous avons également vérifié un appel en lecture seule de la liste des modèles MCP, puis installé, chargé et utilisé la compétence GlobalGPT.
Intégration GlobalGPT · Non prise en compte dans le score de codage
CLI vérifié dans les deux flux de travail ; MCP et Skill vérifiés dans Codex
Cet indicateur mesure les parcours d'intégration, et non pas si GlobalGPT remplace l'un ou l'autre des agents de codage natifs.
| Chemin d'accès | Environnement Codex | Course organisée par les collègues de Claude |
|---|---|---|
| GlobalGPT CLI | Vérifié avec gpt-5.6-sol et gpt-5.6-luna | Vérifié avec les mêmes tâches gelées |
| MCP | Liste interactive des modèles en lecture seule vérifiée | Non connecté pendant la course |
| Compétence | Installé, chargé et testé | Installé mais non utilisé pour les appels en attente |
| MCP sans surveillance | Limite d'autorisation respectée | Non testé |
Consulter l'ensemble des preuves d'intégration
Résumé des tests d'intégration # GlobalGPT Portée de # # Le test T5 évalue l'intégration de GlobalGPT et n'est pas pris en compte dans le score de codage natif de Codex. Yukie n'a pas été utilisé. ## Verrouillage et état de préparation des modèles - Modèle A : `gpt-5.6-sol` - Modèle B : `gpt-5.6-luna` - Les deux modèles figuraient dans la liste des modèles actifs. - Les deux sondes de préparation allégées ont renvoyé un texte valide et analysable. - Les modèles ont été verrouillés avant les appels de sortie formels T5A et T5B. ## Résultats formels de l’interface CLI | Tâche | Modèle | Statut | Durée | Tokens de la prompt | Tokens de la réponse | En-têtes requis | |---|---|---|---:|---:|---:|---:| | T5A | gpt-5.6-sol | Valide | 27 s | 2 116 | 1 207 | 6/6 | | T5B | gpt-5.6-luna | Valide | 14 s | 2 116 | 1 441 | 6/6 | Les deux appels formels ont utilisé la même tâche figée de planification de produit en anglais via `glbgpt exec`, ont renvoyé une sortie visible uniquement en anglais et n’ont divulgué aucune information d’identification. Aucune nouvelle exécution de contrôle qualité n’a eu lieu. ## Résultat MCP - La commande `codex mcp list` a indiqué que `globalgpt` était activé. - Une session Codex non interactive a détecté et tenté d’exécuter `mcp__globalgpt__glbgpt_list_models`, mais l’appel a été annulé car l’approbation MCP sans surveillance n’était pas disponible. Aucun paramètre de sécurité n’a été assoupli. - La session Codex interactive active a appelé avec succès le même outil MCP GlobalGPT en lecture seule et a reçu neuf modèles de chat. - Résultat : accès MCP interactif vérifié ; l’exécution MCP non interactive et sans surveillance reste soumise à une restriction d’approbation. Résultat de la compétence ## - Les compétences GlobalGPT et GlobalGPT Coding sont installées dans le répertoire des compétences Codex via des liens vers le package de compétences CLI fourni. - La compétence GlobalGPT a été chargée et suivie pour la vérification de la session configurée, la sélection de modèles en temps réel, la préparation, les options de sécurité des crédits et la gestion des échecs. - Résultat : installée et testée dans le flux de travail actif de Codex. ## Conclusion limitée Cette exécution vérifie le bon fonctionnement des appels CLI GlobalGPT, un appel MCP GlobalGPT interactif en lecture seule depuis Codex, ainsi qu’un chemin de compétence GlobalGPT installé et utilisé. Elle ne prouve pas que chaque modèle, outil multimédia, hôte, compte ou configuration MCP sans intervention fonctionne. Elle ne teste pas Yukie et ne corrobore pas l’affirmation selon laquelle GlobalGPT remplace Codex ou Claude Code.
Portée vérifiée : appels CLI spécifiques, une lecture interactive de MCP et un parcours de compétence installé/utilisé. Cela ne prouve pas la prise en charge de tous les modèles, outils multimédias, hôtes ou configurations sans intervention.
La limite est importante. L'exécution Claude de notre collègue a permis de vérifier le chemin d'accès CLI, et non le MCP côté Claude. La compétence y était installée, mais n'a pas été utilisée pour les appels mis en attente. Une tentative automatisée via le MCP Codex nécessitait tout de même une validation manuelle. La disponibilité des modèles et les crédits dépendent également du forfait GlobalGPT en cours ; les développeurs doivent donc vérifier la liste en ligne plutôt que de supposer que tous les modèles sont inclus.
GlobalGPT couvre également les images, les vidéos, les fichiers audio et les workflows guidés par l'Agent. Les entrées « Slides », « Document » et « Image » de Yukie constituent une catégorie à part : elles proposent des modèles prêts à l’emploi et des instructions étape par étape dans le navigateur pour les tâches ne nécessitant pas de code. Cela peut s’avérer plus simple que d’ouvrir une interface CLI de programmation pour créer une présentation ou un document structuré, mais cela ne remplace pas la lecture du dépôt, l’exécution de tests ou la révision du code.
Autre catégorie de flux de travail
Tests guidés de l'agent de navigation Yukie
Utile pour les flux de travail Web spécifiques à certaines tâches ; n'a pas été testé en tant que remplacement d'un agent de codage de référentiel.
| Flux de travail | Critères remplis | Premier résultat valide |
|---|---|---|
| Diapositives | 5/6 | Une présentation de cinq diapositives a été générée ; les notes du présentateur n'ont pas pu être vérifiées. |
| Document | 6/6 | Fiche de recherche structurée avec fonction d'exportation et historique des versions. |
| Image + légende | 5/6 | Image carrée bien mise en valeur ; la légende requise était manquante. |
Conclusion fondée : points d'entrée clairs et flux de travail multimodaux guidés. Conclusions non étayées : utilisation illimitée, prix exact ou remplacement complet du code Codex/Claude.
Quel langage de programmation un développeur indépendant devrait-il choisir ?
- Choisissez Codex lorsque l'exécution compacte et bornée, la combinaison des surfaces disponibles ou les données d'exécution disponibles dans votre configuration correspondent à votre façon de travailler.
- Sélectionnez le code Claude lorsqu'une boucle de terminal conversationnelle, les fonctionnalités de personnalisation que vous avez vérifiées ou un comportement de révision plus général, comme celui observé dans notre fixture, revêtent une importance plus grande.
- Utilisez l'une ou l'autre option pour un dépôt que vous ne connaissez pas uniquement après avoir validé l'architecture en lecture seule et évalué les risques. Les deux outils ont bien rempli cette tâche.
- Utilisez les deux de manière sélective lorsqu'un examen par un deuxième agent justifie le coût supplémentaire lié à l'abonnement et à la coordination. Demandez à ce deuxième outil de remettre en question une différence ou un plan plutôt que de se contenter de reproduire aveuglément la tâche.
- Ajouter GlobalGPT lorsque le routage multimodèle ou le traitement multimodal constitue le maillon manquant. Conservez les opérations natives sur le référentiel au sein de l'environnement de développement.
Une période d'essai de sept jours est plus révélatrice qu'un classement. Choisissez une fonctionnalité réelle mais hors production, un bug et une révision. Figez la consigne et la commande de validation. Enregistrez le premier diff valide, les tests réussis, le temps écoulé, les interventions humaines, les implications inattendues et l’impact de ce travail sur votre quota d’utilisation disponible. Le meilleur produit est celui dont vous pouvez détecter les erreurs et dont vous pouvez maintenir le flux de travail.
FAQ : Codex vs code Claude
Le Codex est-il meilleur que le code Claude ?
Pas systématiquement. Les deux ont mené à bien les quatre tâches prévues dans notre programme. Claude Code s'est distingué par l'étendue de son analyse, tandis que Codex s'est révélé plus concis dans certains aspects de la mise en œuvre et de la correction des bogues.
Quelle est la meilleure solution pour les dépôts volumineux ?
Notre petit outil ne peut pas répondre à cette question. Testez les deux dans le cadre d'une tâche en mode lecture seule à partir de votre propre référentiel avant d'autoriser les modifications.
Quel agent de codage nécessite le moins de supervision ?
Cela dépend de la clarté de la tâche, des paramètres du modèle, des instructions du référentiel et du style d'interaction souhaité. Un utilisateur de Reddit a fait état de différents modèles de supervision, mais cette expérience individuelle ne constitue pas une règle applicable à l'ensemble du produit.
Lequel est le moins cher ?
Les principaux niveaux de forfait pour les particuliers correspondent à $20, $100 et $200 par mois, mais les mécanismes relatifs au volume inclus et aux limites diffèrent. Les crédits optionnels et la facturation via l'API sont traités séparément.
Les forfaits Claude et Claude partagent-ils les mêmes limites d'utilisation ?
Oui. Les forfaits Claude et Claude Code sont soumis à des limites de sessions partagées et à des limites hebdomadaires dans le cadre des forfaits Pro ou Max associés.
Les tâches locales et celles exécutées dans le cloud de Codex partagent-elles les mêmes limites ?
Les messages locaux et les discussions sur le cloud partagent un créneau de cinq heures, et des limites hebdomadaires peuvent également s'appliquer.
Le modèle GlobalGPT peut-il remplacer le Codex ou le modèle Claude Code ?
Non. Il permet d'étendre l'un ou l'autre de ces workflows avec des modèles supplémentaires, une interface en ligne de commande (CLI), MCP, des compétences (Skills) et des outils multimodaux, mais l'accès au référentiel et le comportement des agents de codage restent du ressort de l'hôte.
Puis-je utiliser le code GlobalGPT pour les deux produits ?
GlobalGPT propose des tutoriels officiels sur l'interface en ligne de commande (CLI) pour les deux solutions. Nous avons vérifié le fonctionnement de la CLI dans les deux environnements, ainsi que l'utilisation de MCP et de Skill dans Codex, avec une restriction d'autorisation pour MCP en mode sans surveillance.
Les tarifs, les conditions des formules, les intégrations et les sources d'information ont été vérifiés en juillet 2026. Les caractéristiques du produit sont susceptibles d'évoluer.
Ouvert GlobalGPT si vous souhaitez intégrer une approche multimodèle et multimodale à votre processus de codage actuel.


