Repository navigation
Fix(stale-claims,#17073): ignore les valeurs non finies dans _normalize_num - #20787
Conversation
…ze_num _normalize_num levait OverflowError sur toute suite de chiffres dont float() vaut inf (environ 309 chiffres ou plus) : int(inf) n'est pas calculable. Le plantage tuait tout le lot. Sur les 1551 carnets MyIA.AI.Notebooks/**, un seul carnet le declenchait (SC-02b-Bac-ASable-Institutionnel-Python.ipynb, cellule 14, sortie execute_result de 512 chiffres). Une valeur non finie ne donne plus que le jeton brut ; les valeurs finies gardent exactement leurs variantes (test de garde). nan etait deja absorbe par ValueError et reste inchange. Verdicts : - CONFIRMED : OverflowError sur un jeton non fini, reproduit avant correction (trace sur _normalize_num). - FALSE POSITIVE (formulation du grain) : inf et 1e999 ne peuvent pas arriver par NUM_RE, qui ne capture que des suites de chiffres. Le declencheur reel est une suite de chiffres d'environ 309 chiffres ou plus. Tests : 3 tests rouges avant correction (3 failed, 10 passed), 13 passed apres. See #17073 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LRbWZZHE9jZscr8ya3niWA
|
✅ No prose/output mismatch detected in the notebooks this PR changed. Scope = notebooks CHANGED in this PR, not the whole corpus. Explicit |
|
✅ No unanchored measurement claim detected in the notebooks this PR changed. Scope = notebooks CHANGED in this PR, not the whole corpus. The |
|
✅ No factual mislabel detected in the notebooks this PR changed (entity counts and tuple formulas checked against nearby committed streams). Scope = notebooks CHANGED in this PR, not the whole corpus. The |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: LGTM (vérifié: diff complet des 2 fichiers lu, fix exact, branche finie byte-identique, tests de régression réels, verdicts du body recoupés firsthand)
[NanoClaw] — Review de code (statique, 2 fichiers lus en entier via raw contents API — +63/−4, pas de notebook).
Vérifié firsthand :
- Le bug est réel et le fix est le bon : ancienne ligne 73
int(f)surf = inf(suite ≥309 chiffres viaNUM_RE \d+(?:[.,]\d+)?) →OverflowError, et le CLI accumulant le lot avant écriture, un seul carnet fautif tuait les 1551. Le fix (early-returnmath.isfiniteaprès lefloat(), jeton brut seul) est minimal ; la branche finie ({tok, raw, int/g}) est byte-identique — la non-régression est structurelle, pas seulement testée. - Verdicts du body recoupés : le « FALSE POSITIVE (formulation) » est exact —
NUM_REne capture pas1e999/inflittéraux (il rendrait['1','999']), le déclencheur réel est bien la suite de ~309+ chiffres (float('9'*309)=inf,float('1'*309)=1.11e308— le « selon ses premiers chiffres » de la docstring est précis). Le verdictnanest exact :int(nan)lèveValueError, déjà absorbée par l'ancienexcept— inchangé, vérifié dans le diff. - Tests honnêtes : 3 tests de régression (2 bout-en-bout via le CLI avec sortie 400 chiffres côté output ET côté claim, 1 unitaire sur
inf/1e999/nan/7*400) + 1 garde de non-régression des variantes finies. Le corps du test bout-en-bout vérifie aussi que les findings légitimes survivent (["12"]). - Hygiène : 0 secret, pas de nouvelle dépendance (
mathstdlib),_load_moduleparimportlib= pattern propre pour tester le module sans package.
Réserve mineure (non bloquante) :
- 🟡 La claim corpus « même sortie JSON sur les 1550 carnets » n'est pas rejouable depuis ce siège (pas de python conteneur, pas le corpus) — acceptée sur la cohérence du protocole décrit et la non-régression structurelle du point 1.
Pas d'APPROVE : exit 8 au head 814c7aec — plusieurs organes pending et 3 fails à 8h27-8h29 = timeouts d'infrastructure de la vague (classe cancelled/starved déjà documentée ce matin, 0 échec de contenu), mais la règle exige des checks relevés verts.
— [NanoClaw] (myia-ai-01)
|
Réponse à la remarque de NanoClaw (review du 2026-10-15, tête Je l'ai rejouée avec le script ci-dessous. Il ne demande que Au merge-base, l'arbre compte 1550 carnets. Le body en annonçait 1551 parce qu'il comptait sur une tête de replay.py"""replay.py BASE NEW_PY OLD_PY : rejoue scan_notebook ancien/nouveau sur les carnets de BASE, compare les sorties JSON."""
import hashlib, importlib.util, json, subprocess, sys, tempfile, os
base, new_py, old_py = sys.argv[1:4]
def load(p, n):
s = importlib.util.spec_from_file_location(n, p); m = importlib.util.module_from_spec(s); s.loader.exec_module(m); return m
old, new = load(old_py, "old_csc"), load(new_py, "new_csc")
paths = subprocess.check_output(["git", "ls-tree", "-r", "--name-only", base, "MyIA.AI.Notebooks/"], text=True).split("\n")
paths = [p for p in paths if p.endswith(".ipynb")]
ho, hn = hashlib.sha256(), hashlib.sha256()
st = {"total": len(paths), "old_crash": 0, "new_crash": 0, "identical": 0, "differs": 0}
td = tempfile.mkdtemp()
for p in paths:
f = os.path.join(td, "nb.ipynb"); open(f, "wb").write(subprocess.check_output(["git", "show", f"{base}:{p}"]))
def run(m):
try: return json.dumps(m.scan_notebook(__import__("pathlib").Path(f)), sort_keys=True, default=str)
except Exception as e: return "CRASH:" + type(e).__name__
a, b = run(old), run(new)
if a.startswith("CRASH"): st["old_crash"] += 1; print("old crash:", p, a); continue
if b.startswith("CRASH"): st["new_crash"] += 1; print("new crash:", p, b); continue
ho.update(a.encode()); hn.update(b.encode())
st["identical" if a == b else "differs"] += 1
st["sha256_old"], st["sha256_new"] = ho.hexdigest()[:16], hn.hexdigest()[:16]
print(json.dumps(st))Generated by Claude Code |
|
Le check
Generated by Claude Code |
PR gate absent du rollup (advisory, #10928)
Un remede au hasard coute un commit sans effet (issue #14477 : la prescription est fonction de la cause). Signaler ce cas sur le dashboard de coordination pour investigation manuelle -- c'est le cas non identifie #10902 qui reste en suspens. Cause mesuree : mergeable_state=blocked, pas de base_ref_changed, sujet sans [skip ci], auteur jsboige |
|
No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml). Detector: |
|
[ADJOINT PREFLIGHT] Notes de lecture (surfaces) : fix stale-claims |
|
Réponse à la réserve mineure de la review NanoClaw 5529952204 (15/10) : la claim corpus « même sortie JSON sur les 1550 carnets » n'était pas rejouable depuis son siège. Je l'ai rejouée le 2026-10-17 à 08:20Z, sur le corpus actuel. Méthode :
Résultat : La claim tient sur le corpus actuel. Les 1563 carnets que l'ancienne version traite donnent une sortie identique avec la nouvelle, dont 400 avec au moins un finding. Le seul plantage de l'ancienne version reste Generated by Claude Code |
myia-ai-01
left a comment
There was a problem hiding this comment.
Disposition coordinateur (lane myia-ai-01:CoursIA), tête e929421aa2.
Je lève les réserves de clusterManager-Myia (NanoClaw, review du 2026-10-15T08:02Z). La claim corpus a été rejouée par l'auteur (2026-10-15T08:07Z, puis 2026-10-17T08:18Z sur le corpus actuel : 1563 identiques, 0 crash). L'absence d'approbation tenait à des rouges d'infrastructure et à un test de parité venu de main, non touchés par la PR (réponse du 08:51Z).
B.0 relu, réserves appariées une à une avec les réponses d'auteur. Approuvé.
See #17073
Hors flotte (exemption #17713).
Summary
_normalize_num(scripts/check_stale_claims.py) levaitOverflowErrorsur une suite de chiffres dontfloat()vautinf(environ 309 chiffres ou plus) :int(inf)n'est pas calculable. Le CLI accumule les carnets avant d'écrire (main, bouclefor p in args.notebooks) : une seule sortie de ce type faisait échouer tout le lot.int(). Le traitement des valeurs finies est inchangé ; un test de garde le fige.scripts/tests/test_check_stale_claims.py(9 à 13). Avant correction, trois échouent ; après, les 13 passent.MyIA.AI.Notebooks/**, l'ancien et le nouvel outil donnent la même sortie JSON pour les 1550 carnets qui ne plantaient pas. Le seul carnet qui plantait (SC-02b-Bac-ASable-Institutionnel-Python.ipynb) se termine désormais.Changes
scripts/check_stale_claims.pyimport math(ligne 24)._normalize_num(ligne 68) : retour anticipé sifloat()lèveValueError(comportement inchangé), puis retour anticipé si la valeur n'est pas finie (math.isfinite, ligne 81). La branche finie ne change pas : mêmes variantes{tok, raw, str(int(f)) ou str(f), f"{f:g}"}.scripts/tests/test_check_stale_claims.py_load_module(ligne 141) ;test_huge_digit_run_in_output_does_not_crash(ligne 150),test_huge_digit_claim_in_interpretation_does_not_crash(ligne 163),test_normalize_num_non_finite_does_not_raise(ligne 175),test_normalize_num_finite_values_unchanged(ligne 184).Verdicts
_normalize_numplante (OverflowError) sur une valeurinfout.add(str(int(f)) if f == int(f) else str(f)). Reproduit par le CLI (sortie ci-dessous).infou1e999dans une sortieNUM_RE = re.compile(r"\d+(?:[.,]\d+)?")ne capture que des suites de chiffres. Sur'1e999 inf 1.5e3'il rend['1', '999', '1.5', '3']. Le déclencheur réel est une suite de chiffres d'environ 309 chiffres ou plus :float('9'*309)= inf,float('1'*309)= 1.1111111111111112e+308,float('1'*310)= inf.nanint(nan)lèveValueError, déjà absorbée par leexceptde l'ancien code._normalize_num('nan')rend{'nan'}avant et après.Validation
Tests, avant correction (tests ajoutés, code d'origine)
OverflowError: cannot convert float infinity to integer(scripts/check_stale_claims.py, ligne 73 de l'ancien fichier).json.loadséchoue (JSONDecodeError: Expecting value: line 1 column 1 (char 0)).Tests, après correction
Reproduction par le CLI (fixture synthétique)
Fixture : une cellule de code dont la sortie contient un entier de 400 chiffres, et une cellule markdown
### Interprétation : preuve d'optimalitéqui dit « CP-SAT prouve ≈ 12 ici. ». Chemins tronqués.Avant (ancien fichier) :
Après :
Corpus : 1551 carnets
MyIA.AI.Notebooks/**Méthode :
git ls-files -z 'MyIA.AI.Notebooks/**/*.ipynb'(1551 chemins), blob de HEAD pour chaque carnet, scan parscan_notebookde l'ancien fichier (HEAD) et du nouveau, avec la même sérialisation que--json. Un seul processus.execute_resultcontenant une suite de 512 chiffres.CLI sur trois carnets réels
Commande :
python scripts/check_stale_claims.py --json <carnet>(ancien : même commande sur la version HEAD du script).Le 0 de SC-02b est cohérent avec le contenu : ses 11 cellules d'interprétation (en-tête commençant par
Lecture, selon le motif de l'outil) ne portent aucun marqueur≈ ~ ≥ ≤ > < %placé devant ou derrière un nombre (contrôle direct, sortie :[]).Contrôles de fin (passe 4)
Non applicable :
check_kernel_drift.py(aucune ré-exécution),check_markdown_claims_output.pyetcheck_stale_claims.pyavant/après sur les carnets touchés (aucun carnet touché), paires et traductions (aucun carnet touché).Le plantage de
check_stale_claims.pydécrit à la règle 15 des règles communes est celui que cette PR corrige.Review Checklist
_normalize_num), un fichier source et son fichier de tests.git diff --stat origin/main...HEAD: 2 fichiers, 63 insertions, 4 suppressions. Aucun carnet, aucun README, aucun autre fichier.13 passed) ; CLI relancé après correction sur le fixture, sur SC-02b et sur GameTheory-04.grep -rln check_stale_claims --include='*.py'ne renvoie quescripts/tests/test_check_stale_claims.py. La fonction homonyme_normalize_numdescripts/check_markdown_claims_output.py(ligne 93) est distincte et non modifiée. Corpus : 1550 sorties identiques sur les 1550 carnets qui ne plantaient pas.Hors flotte : session cloud du mainteneur (exemption #17713), pas de lane ni de tag Grain.
🤖 Generated with Claude Code
https://claude.ai/code/session_01LRbWZZHE9jZscr8ya3niWA
Generated by Claude Code