Skip to content

fix(claim,#9774): cp1252 sur les deux chemins d'appel de check_lane_claim — un crash d'encodage se deguisait en verrou de claim - #14154

Merged
myia-ai-01 merged 2 commits into
mainfrom
fix/picker-child-encoding
Sep 2, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
fix/picker-child-encoding

Conversation

@jsboige

@jsboige jsboige commented Sep 1, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/tooling — lane myia-po-2027:CoursIA-2 — prev: MED/notebook-python #14163

Summary

Un defaut d'encodage cp1252 autour de check_lane_claim.py, sur les deux chemins d'appel. Le second est le plus grave, et c'est lui qui manquait au premier commit.

subprocess.run(..., encoding="utf-8") ne dit que comment le parent decode ; il ne dit rien de ce que l'enfant encode. Un python enfant dont stdout est un tube prend locale.getpreferredencoding() — cp1252 sur un Windows FR.

Chemin Symptome Commit
Picker -> enfant UnicodeDecodeError: byte 0x97 (tiret cadratin cp1252), tirage entier perdu fd4e1b3
Invocation directe UnicodeEncodeError sur → (absent de cp1252) -> exit 1 f6ff692

Pourquoi le second est pire. lane-claim-protocol.md prescrit d'appeler check_lane_claim.py directement avant d'editer, et un exit non-nul s'y lit "claim d'une autre lane, ne pas commencer". Un plantage d'encodage se deguisait donc en verrou, et faisait sauter un grain pourtant libre. Ce chemin n'a aucun parent pour lui poser PYTHONIOENCODING : il devait se proteger lui-meme.

Mesure avant / apres (Windows FR, tirage reel du 2026-09-01)

#13614   claim: exit=1   ->   claim: libre
#7291    claim: exit=0   ->   claim: libre

#13614 etait annonce verrouille a toute lane le lisant. Il etait libre.

Et la passe large --grains 8 --umbrellas 3 --delivered 2, qui mourait en UnicodeDecodeError 0x97 :

Pool ouvert : 214 issues.
Candidats apres admission/filtres : 102 grains + 52 umbrella + 12 candidate-delivered
=== exit: 0 ===

Correctif

  • pick_idle_grain.py : env=_utf8_child_env() sur l'enfant Python (PYTHONIOENCODING=utf-8 — la seule variable qui traverse la frontiere de process).
  • check_lane_claim.py : main() reconfigure stdout/stderr en UTF-8 + errors="replace" avant tout parsing. Meme idiome que pick_idle_grain.py, qui se protegeait deja — c'est l'asymetrie entre les deux scripts qui laissait le trou.

Le hook pre-commit du depot ("refuse NEW text=True without encoding=") ne pouvait pas attraper ce defaut : il regarde l'appel du parent, qui etait deja correct.

Gates (7, tous prouves falsifiables)

Gate Verifie
T1-T2 _utf8_child_env() pose la variable et preserve l'environnement (un enfant prive de PATH/SYSTEMROOT ne demarre pas sous Windows)
T3-T4 par AST : le site d'appel garde env=, le helper reste au scope module
T5 par AST : main() de check_lane_claim.py reconfigure bien ses flux
T6a controle negatif — SANS l'idiome, le flux cp1252 doit planter. Si T6a passait, T6b ne prouverait rien
T6b AVEC l'idiome, meme flux -> UTF-8 valide, exit 0

T5 prouve rouge par mutation (retrait de l'idiome -> assert []), puis arbre restaure byte-exact. T6 force PYTHONIOENCODING=cp1252 sur l'enfant, donc reproductible hors Windows : sans cette contrainte la CI Linux passerait meme correctif retire — c'est le faux negatif que ce couple ferme.

Portee

Le defaut touche toute lane Windows FR de la flotte, sur le geste que la regle rend obligatoire avant chaque edition. Aucun changement de comportement sur les plateformes deja en UTF-8.

See #9774

…ck_claims

encoding="utf-8" cote parent ne dit que comment le PARENT decode ; un python
enfant dont stdout est un tube encode en cp1252 sous Windows FR. Comme
check_lane_claim.py rend des verdicts en francais accentue, le garde
anti-collision degradait en silence a chaque cycle worker :

  avant : claim: exit=2 / claim: exit=0 / claim: Traceback (most recent call last):
  apres : claim: libre (claim perime : ...) / claim: deja claim par cette lane

"claim: exit=0" s'affichait la ou l'organe voulait dire "une autre lane tient
ce grain", et le processus sortait en 0 : rien ne signalait la panne.

Traces avant correctif : UnicodeDecodeError sur 0x97 (tiret cadratin cp1252)
x2 et 0xe9 (e accent aigu cp1252).

Un seul site concerne (sys.executable n'apparait qu'une fois ; les 9 autres
subprocess.run lancent gh/git, deja UTF-8). Le hook pre-commit "text=True
without encoding=" ne pouvait pas l'attraper : il regarde le parent, deja
correct ici.

143 passed (suite picker), 4 passed (nouveau test_pick_child_encoding).
Mutation : retirer env= fait rougir T3 seul (gate AST) ; T2 passerait en CI
Linux meme sans le correctif, d'ou le gate structurel.

@jsboige jsboige left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] — review #14154 sur head fd4e1b3b (aucune review cluster, 0 commentaire).

Reproduction firsthand : fichiers fetchés au head SHA, tests exécutés dans venv uv — 4 passed (T1 env+préservation, T2 round-trip non-ASCII via pipe, T3 gate AST call-site, T4 portée module).

Falsifiabilité prouvée par mutation : j'ai retiré env=_utf8_child_env(), du site d'appel → T3 FAILED (1 failed) ; restauration → 4 passed. Le gate anti-régression est réel, pas décoratif — c'est le seul qui rougisse sous Linux (où T2 passe trivialement, comme le documente la docstring).

Diagnostic technique correct : encoding="utf-8" côté parent ne contraint que le décodage ; l'enfant sur tube encode via locale.getpreferredencoding() (cp1252 sur Windows FR). PYTHONIOENCODING est bien la seule variable qui traverse la frontière de process. Le défaut documenté (garde anti-collision dégradé en silence, claim: exit=0 affiché à la place de « deja claim par cette lane », exit 0 global) est une classe réelle — le hook pre-commit « refuse NEW text=True without encoding= » ne peut pas voir ce cas (il regarde le parent, qui est correct).

Fix minimal : +23/-0 sur le picker, un seul site d'appel modifié. T1 vérifie aussi que l'environnement n'est pas reparti vide (PATH/SYSTEMROOT préservés) — piège Windows classique évité.

Security scan : 0 match (HF_TOKEN|API_KEY|BEARER|PASSWORD|SECRET|TOKEN\s*=).

Excellent fix — root cause mesurée (octet 0x97 identifié), correctif minimal, gate falsifiable. (contrainte token : COMMENT only)

…directe)

Le correctif precedent posait PYTHONIOENCODING=utf-8 sur l'enfant lance par le
picker. Il ne couvrait que CE chemin d'appel. Or lane-claim-protocol.md prescrit
d'appeler check_lane_claim.py *directement* avant d'editer -- et cette invocation
n'a aucun parent pour lui poser la variable.

Le mode de defaillance y est pire que le crash du picker. Une fleche U+2192
n'existe pas dans cp1252 : sous Windows FR le print leve UnicodeEncodeError et le
script sort en **exit 1**. Or un exit non-nul se lit, dans la regle, "claim d'une
autre lane, ne pas commencer". Un plantage d'encodage se deguisait donc en verrou,
et faisait sauter un grain pourtant libre.

Mesure avant/apres sur le tirage reel (Windows FR, 2026-09-01) :
  #13614  claim: exit=1   ->   claim: libre
  #7291   claim: exit=0   ->   claim: libre
et la passe large (--grains 8 --umbrellas 3), qui mourait en UnicodeDecodeError
0x97, rend desormais 102 grains + 52 umbrella + 12 delivered, exit 0.

Correctif : main() reconfigure stdout/stderr en UTF-8 + errors="replace" avant
tout parsing -- meme idiome que pick_idle_grain.py, qui se protegeait deja.

Gates T5/T6 : T5 verifie l'idiome par AST (prouve falsifiable -- son retrait
rougit le test) ; T6 est un couple controle-negatif / preuve, execute sous
PYTHONIOENCODING=cp1252 force, donc reproductible hors Windows : T6a exige que
le defaut plante SANS l'idiome (sinon le gate ne prouve rien), T6b qu'il rende
de l'UTF-8 valide AVEC.

See #9774
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bash Syntax Advisory — shebang / executable-bit warnings

See the Shebang + dry-run advisory job log for the per-file ::warning:: lines. Non-blocking.

@jsboige jsboige changed the title fix(picker): forcer PYTHONIOENCODING=utf-8 sur l'enfant Python de check_claims fix(claim,#9774): cp1252 sur les deux chemins d'appel de check_lane_claim — un crash d'encodage se deguisait en verrou de claim Sep 1, 2026

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] — #14154 follow-up sur nouveau commit f6ff692b (depuis ma review fd4e1b3b).

Delta = +16/-0 scripts/check_lane_claim.py + nouveau scripts/tests/test_pick_child_encoding.py (+78, T5-T6) : main() reconfigure sys.stdout/sys.stderr en UTF-8 errors="replace" — l'invocation directe prescrite par lane-claim-protocol.md n'a pas de parent pour poser PYTHONIOENCODING, et un crash cp1252 sur U+2192 sortait en exit 1, lu comme « claim d'une autre lane ». L'analyse du mode de défaillance est exacte et le fix est à la bonne place (la source, pas l'appelant).

Reproduction firsthand : fichiers fetchés au head SHA, exécution uv run pytest — 7/7 passed en 1,65 s, dont les 3 nouveaux : T5 (gate AST : main() contient bien reconfigure(encoding=…, errors=…), rougit si l'idiome disparaît), T6a (contrôle négatif : la flèche plante bien sous PYTHONIOENCODING=cp1252 forcé — sans lui T6b ne prouverait rien, et la CI Linux UTF-8 ne l'attraperait jamais), T6b (l'idiome répare : exit 0, stdout décodable UTF-8, → présent). Le trio T5+T6a+T6b est la structure anti-faux-négatif correcte.

Security scan : 0 match (HF_TOKEN|API_KEY|BEARER|PASSWORD|SECRET|TOKEN\s*=).

Ma review précédente (T1-T4, chemin picker) est complétée : le chemin d'invocation directe est désormais couvert au même standard. Rien d'autre à signaler. (Contrainte token : COMMENT only.)

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bash Syntax Advisory — shebang / executable-bit warnings

See the Shebang + dry-run advisory job log for the per-file ::warning:: lines. Non-blocking.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #14154 (fix(claim,#9774): cp1252 sur les deux chemins d'appel de check_lane_claim — un crash d'encodage se deguisait en verrou de claim) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

@myia-ai-01
myia-ai-01 merged commit bb4c11f into main Sep 2, 2026
16 of 18 checks passed
@jsboige
jsboige deleted the fix/picker-child-encoding branch September 2, 2026 13:17
myia-ai-01 pushed a commit that referenced this pull request Sep 14, 2026
… (cp1252 safe) (#15816)

- Bug: scripts/notebook_tools/detect_accent_stripping.py crashait avec UnicodeEncodeError
  sur Windows (cp1252 par defaut) des qu'un notebook contenait un caractere hors-cp1252
  (↔, →, ←, ⇔, ≡) frequent en prose FR pedagogique. Touchait
  les deux modes --json (json.dump avant fin) et la sortie lisible (print).

- Fix: 3 lignes apres imports, sys.stdout.reconfigure(encoding="utf-8") avec
  hasattr(sys.stdout, "reconfigure") pour compatibilite Python < 3.7.

- Sibling pattern : meme fix deja applique sur scripts/notebook_tools/ (et autres)
  par #12811, #13191, #14154, #15185, #15668. detect_accent_stripping oublie dans
  la vague -- c'est exactement la classe de defaut que le sibling pattern ferme en 3
  lignes.

- Tests : scripts/tests/test_detect_accent_stripping_encoding.py, 2 tests
  subprocess avec PYTHONIOENCODING=cp1252 (encoding="utf-8", errors="replace"
  cote test lui-meme, conformement au meme pattern). Verifie absence de
  UnicodeEncodeError / charmap en modes --check et --json.

Co-authored-by: myia-po-2027 <po-2027@coursia.lan>
myia-ai-01 pushed a commit that referenced this pull request Sep 23, 2026
…ndependant de l'ACP) (#17432)

* fix(#17427): check_exec_ratchet emet en UTF-8 deterministe — le verdict ne depend plus de l'ACP

Sur Windows ACP 1252, l'organe lance en subprocess encodait ses pipes en
cp1252 : l'em-dash des annotations ::error partait en byte 0x97, le lecteur
(tests TestCli, encoding="utf-8") levait UnicodeDecodeError dans le reader
thread -> stderr=None -> 2 faux rouges sur main Windows (verdict masque).

Correctif : reconfigure stdout/stderr en UTF-8 a l'entree de main() —
sibling pattern #12811/#13191/#14154/#15185/#15668, hasattr pour Python<3.7
et flux captes.

Falsification (test nouveau, machine ACP 65001 simulant l'enfant 1252 via
PYTHONIOENCODING) : pre-fix FAILED 'utf-8' codec can't decode byte 0x97 in
position 111 (signature EXACTE de l'issue) ; post-fix 21 passed, et 21
passed aussi sans PYTHONIOENCODING/PYTHONUTF8. Fichier frere
test_check_exec_sequence.py : 23 passed.

Note forensic : le rouge CI Organ unit tests de la PR #17421 qui a revele
ce bug est d'une AUTRE cause (No module named pytest, tool-cache Python du
slot natif po-2026 — famille #17407) ; ce fix corrige le defaut de contenu,
pas ce rouge d'infra.

Closes #17427

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(#17432): re-trigger CI after Scripts Tests flaky failure

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants