Rejeu du bras kit-gov après le lot K — les excursions reculent, aucun critère de sortie n'est atteint — 2026-09-29¶
Issue #642 (plan produit 2026-Q4, phase 2bis « Cœur », lot K, suite directe du lot J — #582). Commit rejoué :
main@d22807d0(release 3.61.0), qui inclut le correctif du lot K (#651 : messageacceptance.no_tests_collectedsans injonction, repli--task-idnommant le board plutôt que d'évaluer une tâchebootstrapfantôme) mergé le 2026-09-28, avant ce rejeu. Bras rejoué :kit-govuniquement (--arms kit-gov --resume,scripts/bench/three_arms.py, graine 551, mêmes 20 tâches) ; brasnu/ecc/kitrepris tels quels du lot J (docs/bench/rejeu-lot-j-2026-09-18.md), aucun nouveau run, aucun coût. Binaire mesuré :grimoire3.61.0 installé (roue publiée), invoqué par chemin absolu (--grimoire-bin), pas le worktree éditable — contrairement aux lots F-J qui rejouaient un worktree jetable, ce lot mesure directement le code publié. Données brutes locales (Grimoire-Forge, hors dépôt kit), non poussées :_scratch/bench-k/workspace/state/{results.jsonl,selection.json},_scratch/bench-k/workspace/reports/2026-09-29/{report.md,report.json}. Coût de la campagne : 33,72 $ (60 runskit-gov, seul bras rejoué), aucun incident (0 run à erreur ou coût nul, disque toujours > 400 Go libres, 60/60terminated_reason: "completed"). Verdict : aucun des quatre critères chiffrés de l'issue #642 n'est atteint. Part des runs « avec excursion » 26,7 % (16/60, contre 30 % au lot J — recul réel mais loin du seuil < 10 %) ; coût médian/tâche résolue ≈122 % du nu (contre ≈112 % au lot J — dégradation) ; succès 90,0 % (contre 96,7 % au lot J et 91,7 % pournu— dégradation) ;gate checkvert au dernier appel sur 60/60 (seul critère atteint, déjà acquis au lot J). Décision proposée en §7, pas appliquée unilatéralement.
1. Méthode¶
1.1 Code rejoué¶
- Worktree jetable
_scratch/wt-bench-k(git worktree add … origin/main -b docs/bench-lot-k),origin/mainfraîchement fetché, HEAD àd22807d0(3.61.0) — inclut le correctif du lot K (#651), mergé la veille de ce rejeu. Contrairement aux lots F à J, le harnais n'a pas tourné contre un worktree éditable : le binaire mesuré (--grimoire-bin /mnt/…/rel-check-3610/venv/bin/grimoire,grimoire --version= 3.61.0) est la roue publiée, exactement ce qu'un projet consommateur installe. - Bras
nu/ecc/kitnon rejoués : les 180 lignes du lot J (_scratch/bench-j/workspace/state/results.jsonl) ont été copiées dans_scratch/bench-k/workspace/state/results.jsonlavant tout lancement, ligneskit-govretirées de la copie pour que--resumene rejoue que ce bras (même mécanisme que le lot J, qui reprenait lui-même les brasnu/ecc/kitdu lot F). - Authentification
--auth oauth-copy(pas de clé API dans l'environnement de lancement) — mode historique, seul mode disponible ici ; surveillé en continu (jalons 20/40/60 runs) pour la rotation de jeton qui avait coûté 30 runs à 0 $ au lot J : aucune occurrence cette fois, campagne continue de bout en bout. - Toolchains (Go, Rust, Node/npm, Python) et environnement agent/harnais partagé (
run_environment(), lot I) inchangés par rapport au lot J ;verify_agent_toolchain_environmenta confirmé les quatre langues disponibles avant le premier appelclaude -p(table §1.2 du rapport du harnais, toutes « toolchain disponible »).
1.2 Aucun incident¶
Les 60 runs kit-gov se terminent en terminated_reason: "completed" (60/60), 0 ligne à coût nul, jamais moins de
400 Go libres sous _scratch. Une seule exécution continue, jalonnée à 20, 43 puis 60 runs pour vérifier l'absence
d'expiration OAuth en cours de campagne (défaut du lot J, §1.2 de son rapport) — jamais observée ici.
2. Résultats agrégés¶
| Bras | Runs | Succès | IC95 % succès | pass^k | Temps médian | Tours médians | Coût médian/tâche résolue | Coût total | test-run.json (lot B) |
Gate vert au dernier appel | Friction toolchain médiane |
|---|---|---|---|---|---|---|---|---|---|---|---|
| nu | 60 | 91,7 % | [85 %, 98 %] | 90 % | 64 s | 6,0 | 0,399 $ | 27,04 $ | s.o. | s.o. | s.o. |
| ecc | 60 | 93,3 % | [87 %, 98 %] | 90 % | 61 s | 7,0 | 0,629 $ | 45,30 $ | s.o. | s.o. | s.o. |
| kit | 60 | 90,0 % | [82 %, 97 %] | 85 % | 57 s | 6,0 | 0,416 $ | 30,26 $ | 0 % (jamais gouverné) | s.o. | s.o. |
| kit-gov (lot J, 2026-09-18) | 60 | 96,7 % | [92 %, 100 %] | 95 % | 51 s | 6,0 | 0,445 $ | 31,98 $ | 75,0 % | 100 % (60/60) | 1,0 (37 appels/60 runs) |
| kit-gov (lot K, 2026-09-29) | 60 | 90,0 % | [82 %, 97 %] | 85 % | 78 s | 7,0 | 0,488 $ | 33,72 $ | 75,0 % | 100 % (60/60) | 1,0 (54 appels/60 runs) |
Nouvelle métrique de ce lot — part des runs « avec excursion » (définition de l'issue #642, reprise et vérifiée sur
le lot J avant application ici, script scripts/bench/excursions.py : un run est « mandat pur » si son seul appel
grimoire … standard gate check réel est le dernier appel outil de la session, « avec excursion » sinon — plusieurs
appels gate, ou tout appel outil après le premier) :
| Lot | Runs « avec excursion » | Part | Surcoût total lot−nu porté par les excursions |
|---|---|---|---|
| J (2026-09-18) | 18/60 | 30,0 % | 103 % (+4,95 $ sur +4,94 $ total) |
| K (2026-09-29) | 16/60 | 26,7 % | 37 % (+2,45 $ sur +6,68 $ total) |
Rejeu : python scripts/bench/excursions.py --workspace <dossier du banc> --arm kit-gov --reference-arm nu (option --json pour le détail par run ; le dossier du banc contient state/results.jsonl et tasks/).
Le nombre d'excursions recule (18 → 16) et leur poids relatif dans le surcoût recule fortement (103 % → 37 %), mais le
surcoût total J−nu → K−nu augmente (+4,94 $ → +6,68 $) : les runs « mandat pur » eux-mêmes coûtent désormais plus cher
qu'au lot J (surcoût médian mandat pur : +0,039 $ au lot J, +0,098 $ au lot K — plus du double) alors que la
définition du mandat n'a pas changé entre les deux lots. Le fichier report.json ne distingue pas la cause ; hypothèse
non vérifiée par ce lot : dérive d'environnement entre le 2026-09-18 et le 2026-09-29 (versions de cargo/npm/go
sur la machine de lancement), pas nécessairement un effet du correctif #651 — voir §6.
3. Par langue¶
| Langue | Tours médians nu | Tours médians kit-gov J | Tours médians kit-gov K | Coût médian kit-gov K |
|---|---|---|---|---|
| go | 6 | 6 | 7 | 0,475 $ |
| javascript | 5 | 9 | 6 | 0,503 $ |
| python | 4 | 5 | 6 | 0,466 $ |
| rust | 6 | 6 | 8 | 0,683 $ |
Seul mouvement net favorable : javascript (9 → 6 tours médians, se rapproche de nu à 5) — cohérent avec l'effet
attendu du correctif #651 sur le WARN acceptance.no_tests_collected, le déclencheur documenté par l'issue pour 15/15
runs JavaScript du lot J. go (6 → 7), python (5 → 6) et rust (6 → 8) régressent tous, dans une fourchette
que ce lot n'attribue à aucune cause précise (aucun de ces trois langages n'était visé par le correctif #651).
4. Par tâche¶
| Tâche | Langue | nu | ecc | kit | kit-gov (J) | kit-gov (K) |
|---|---|---|---|---|---|---|
| go/bottle-song | go | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| go/error-handling | go | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| go/palindrome-products | go | 0/3 | 2/3 | 1/3 | 3/3 | 2/3 |
| go/pov | go | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| go/simple-linked-list | go | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| javascript/affine-cipher | javascript | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| javascript/go-counting | javascript | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| javascript/list-ops | javascript | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| javascript/queen-attack | javascript | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| javascript/transpose | javascript | 3/3 | 3/3 | 2/3 | 1/3 | 1/3 |
| python/bowling | python | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| python/list-ops | python | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| python/proverb | python | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| python/react | python | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| python/zipper | python | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| rust/forth | rust | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| rust/poker | rust | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| rust/react | rust | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| rust/scale-generator | rust | 1/3 | 0/3 | 0/3 | 3/3 | 0/3 |
| rust/two-bucket | rust | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
Deux mouvements notables par rapport au lot J, tous deux sur des tâches déjà marginales aux lots précédents (nu/ecc/kit
échouaient déjà dessus avant le lot I) :
rust/scale-generator(3/3 → 0/3), la régression la plus nette de ce lot. Le gatekit-govreste vert à chaque run (cargo testexécuté, exit 0, enregistré danstest-run.json) — la solution passe la suite visible par l'agent et par le gate. Le verdictsuccessdu harnais, qui rejoue la vraie suite Exercism masquée du dépôt de tâche, la classe pourtant en échec sur les 3 runs. Signature identique à celle documentée aux lots F/H avant le lot I (« suite compilée à 0 test réellement exécutés ») : la disparition d'un fichier de test réel entre l'exécution du lot J et celle-ci n'a pas été vérifiée par ce lot (pas de diff depolyglot-benchmarkinspecté) — cause non tranchée, à reprendre avant tout nouveau rejeu si elle se reproduit.go/palindrome-products(3/3 → 2/3) : un des deux runs KO (run1,run2) ouvre sur un premiergate checken échec (first_gate_ok: False), même défaut de repli sur le board que celui déjà nommé au lot J pourrust/poker run2— un appel de plus après ce premier échec (1 appel, pas une spéléologie de 22 tours), donc classé « avec excursion » mais d'un ordre de grandeur très inférieur à l'incident du lot J.javascript/transposereste à 1/3, cause inchangée depuis les lots F/H/J (auto-vérification par un script ad hoc au lieu de la vraie suite Exercism masquée, cf. rapport du lot J §4) — rien dans ce lot ne touche à ce mécanisme.
5. Ce que change (et ne change pas) le correctif #651¶
- Ce qu'il corrige, visible : plus aucune occurrence du texte « écris un test » ni « justifie » dans les sorties de gate JavaScript (recherche exhaustive sur les 60 dernières sorties de gate, comme au lot J) — le déclencheur nommé par l'issue pour 15/15 runs JavaScript du lot J a disparu, et les tours médians JavaScript reculent en conséquence (9,0 → 6,0, §3).
- Ce qu'il ne corrige pas : la définition « mandat pur » de l'issue (un seul appel gate, rien après) exclut aussi
un run qui enchaîne un appel bénin après un gate déjà vert — par exemple
javascript/affine-cipher run0lancenpx eslintaprès ungate checkvert (§2, scriptscripts/bench/excursions.py). Sur les 16 runs « avec excursion » du lot K, 10 ont un gate vert dès le premier appel et un seul appel supplémentaire (souvent un lint ou une relecture finale) — un ordre de grandeur sans rapport avec les boucles de 3 à 22 tours du lot J. Cette catégorie n'est pas nommée par l'issue #642 et n'est donc pas résolue par son critère binaire actuel. - Le repli
--task-id bootstrap(deuxième volet du correctif #651) n'a été sollicité par aucun run de cet échantillon (aucune cartebootstrapmanquante rencontrée sur les 60 runs) — non mesurable sur ce banc, comme au lot J pour d'autres mécanismes ponctuels.
6. Verdict, sans arbitrage¶
Critères chiffrés de l'issue #642 :
| Critère | Cible | Lot J (référence) | Lot K (ce rejeu) | Atteint |
|---|---|---|---|---|
| Part des runs « avec excursion » | < 10 % | 30,0 % (18/60) | 26,7 % (16/60) | Non |
| Coût médian/tâche résolue | ≤ 105 % du nu | ≈112 % | ≈122 % | Non |
| Succès | ≥ 96,7 % | 96,7 % | 90,0 % | Non |
gate check verts au dernier appel |
60/60 | 60/60 | 60/60 | Oui |
Un seul des quatre critères est atteint (déjà acquis au lot J, non affecté par ce lot). Les trois autres reculent ou
stagnent loin de la cible : les excursions diminuent en nombre et en poids relatif dans le surcoût (§2), mais le
surcoût total et le taux de succès se dégradent par rapport au lot J, sur des causes que ce rapport documente (§4, §5)
sans toutes les trancher — en particulier la régression rust/scale-generator (§4) et le surcoût accru des runs
« mandat pur » eux-mêmes (§2), qui ne sont pas des effets attendus du correctif #651 tel que décrit par l'issue.
Ce rapport ne propose pas de dégeler la phase 2bis sur ce résultat : à la lettre des quatre critères, ce lot ne clôt
pas l'issue #642. Décision (rouvrir l'analyse causale sur rust/scale-generator et le surcoût élargi, redéfinir la
catégorie « excursion bénigne » à un seuil de coût plutôt qu'à une présence binaire d'appel, ou classer le lot comme
non concluant sans nouveau rejeu immédiat) : à Guilhem.
7. Ce qui reste¶
- Cause de la régression
rust/scale-generator(§4) non tranchée : comparer l'état depolyglot-benchmarkentre le 2026-09-18 et le 2026-09-29 (le clone est fait à chaque campagne,--depth 1surHEADdu dépôt tiers), ou l'état des toolchains (cargo/rustc) de la machine de lancement. - Cause du surcoût accru des runs « mandat pur » (+0,039 $ → +0,098 $ médian, §2) non tranchée — vérifier si elle est généralisée (dérive de tarification ou de contexte de session Claude Code) ou localisée à quelques tâches.
- La distinction entre « excursion coûteuse » (boucle de plusieurs tours, cas du lot J) et « appel bénin après un gate vert » (cas majoritaire des excursions du lot K, §5) n'est pas représentée par le critère binaire actuel de l'issue #642 — matière à une définition affinée si un nouveau lot est ouvert sur ce sujet.