Skip to content

fix(argumentation_lib,#4960): alias de routage tweety_initializer -- la couche AF cesse d'etre morte a l'import - #21657

Open
jsboige wants to merge 4 commits into
mainfrom
fix/arglib-afhandler-import-alias
Open

jsboige wants to merge 4 commits into
mainfrom
fix/arglib-afhandler-import-alias

Conversation

@jsboige

@jsboige jsboige commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/test — lane myia-po-2023:CoursIA — prev: DEEP/notebook-python #21650

Sujet

La couche AF de argumentation_lib est morte à l'import depuis le merge C186f — mesuré firsthand :

>>> from argumentation_lib._af_handler import AFHandler
ModuleNotFoundError: No module named 'argumentation_lib.tweety_initializer'

_af_handler.py (copie verbatim amont, SHA1 c8c468e, en-tête « verbatim copy ») importe le sibling sous son nom amont from .tweety_initializer import TweetyInitializer, alors que le module livré par la sub-tranche C186f porte le préfixe underscore : _tweety_initializer.py. Conséquence : get_af_handler_symbol() — l'accessoire lazy que le __init__.py exporte — promet une couche qui ne peut pas se charger. Périmètre : 2 fichiers (argumentation_lib/__init__.py, tests/test_af_handler_import_alias.py), aucun autre changement.

Ce qui est livré

  • L'alias de routage que la notice DEPENDENCY du fichier verbatim annonce elle-même (« future CoursIA shim will re-route ») : sys.modules.setdefault("argumentation_lib.tweety_initializer", _tweety_initializer) posé par la couche shim __init__ (CoursIA-authored, pas verbatim). La copie amont reste byte-for-byte intacte — zéro édition de _af_handler.py.
  • 4 tests de contrat (test_af_handler_import_alias.py) : l'import documenté comme échouant réussit ; l'alias EST le module C186f (identité d'objet) ; l'accessoire lazy d'accord avec l'import direct ; l'import du package reste sans JVM et sans effet de bord (sonde sous-processus, isJVMStarted() == False).

Validation

  • Suite argumentation_lib complète : 329 passed (les 4 nouveaux inclus) — python -m pytest tests/ -q depuis Argument_Analysis/.
  • Voie complète consommateur vérifiée (script jetable, JVM démarrée par le pont Tweety du carnet ICT C3) : TweetyInitializer().ensure_jvm_and_components_are_ready() → AFHandler(init) → analyze_dung_framework(..., semantics="grounded") rend les extensions conformes aux témoins en dur : chaine 5 → {a0, a2, a4}, cycle 2 → ∅, auto-attaque → ∅.
  • Pas de notebook touché, pas de kernel requis pour la suite.

Empilement

Autonome sur main. Consommateur visé : la jonction Argumentum du carnet ICT C3 (#7742, tranche suivante — la §8sexies a validé contre TweetyProject brut, la jonction restante valide contre l'organe EPITA argumentation_lib ; cet en-tête en est le prérequis).

See #4960 (EPIC vendoring argumentation_lib, sub-tranches C186d/C186f) · See #7742 (consommateur)

Correction post-CI — l'alias ne rend plus jpype obligatoire (commit 4e2ec66cc5)

Le premier passage CI a revele une regression du correctif : l'enregistrement eager de l'alias importait _tweety_initializer (qui importe jpype en tete de module) a l'import du paquet. Sur le job Scripts Tests (CPU) — ou jpype n'est pas installe — six modules de tests Argument_Analysis echouaient a la collecte (ModuleNotFoundError: No module named 'jpype') et le PR gate tombait avec eux (pr-gate FAIL -- failing checks: Scripts Tests (CPU)).

Correctif : l'alias degrade proprement. __init__.py enveloppe l'import dans try/except ImportError ; sans jpype, l'alias n'est pas enregistre (la couche AF est de toute facon indisponible, _af_handler important jpype lui aussi), et le reste du paquet — ainsi que les modules de tests qui l'importent — reste importable.

  • Les 4 contrats AF passent en skipif(not jpype).
  • Nouveau contrat test_package_import_survives_missing_jpype : reproduit l'absence de jpype par un meta_path blocker dans un sous-processus et exige que l'import du paquet reussisse et que l'alias ne soit pas enregistre.
  • Reproduction CI sans jpype (6 modules concernes) : 174 passed, 4 skipped, 0 error — avant correctif : 6 erreurs de collecte. Avec jpype : 5 passed sur le module de contrat.

🤖 Generated with Claude Code

…la couche AF cesse d'etre morte a l'import

_af_handler.py (copie verbatim amont, c8c468e) importe le sibling
'from .tweety_initializer import TweetyInitializer' alors que le module
livre par C186f porte le prefixe underscore. Depuis le merge C186f,
l'import de la couche AF echoue au chargement (ModuleNotFoundError:
No module named 'argumentation_lib.tweety_initializer') -- la couche
que get_af_handler_symbol promet est morte a l'arrivee, mesure firsthand.

Le geste annonce par la notice DEPENDENCY du fichier verbatim (le shim
CoursIA re-route) : alias sys.modules dans la couche shim __init__, la
copie amont reste byte-for-byte intacte. Contrat tenu par 4 tests
(import, identite d'alias, accord de l'accesseur lazy, securite
package-import sans JVM, subprocess encoding utf-8) ; suite
argumentation_lib : 329 passed. Voie complete verifiee : AFHandler +
TweetyInitializer sur JVM deja demarree, extensions grounded conformes
aux temoins (chaine 5 {a0,a2,a4}, cycle 2 vide, auto-attaque vide).

See #7742 (consommateur : jonction Argumentum du carnet ICT C3)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-po-2023:CoursIA a deja consomme son budget LIGHT du jour (#20599 (merge a 2026-10-20T19:57:09Z)).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour,
toutes categories LIGHT confondues
(guard, doc, refs, ... partagent un seul budget) :
c'est un RATIO, pas un plafond plat. La decision de merge reste au coordinateur.

@github-actions github-actions Bot added the trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) label Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Trivial-diff advisory (#15740, non bloquant).
genre test dans la famille META (docs/guard/ledger/readme/test) + diff de 95 lignes changees (<= 100) + aucune exception ecrite dans le body : le litmus de la trivialite (une douzaine d'instances scannees a la suite) est credible. Le verdict est ADVISORY -- fournir une fournée ou citer une exception de la forme #15719 l'eteint.
La demande : une fournee (le geste pourrait comprendre ~10x plus d'instances), OU une exception ecrite dans le body de la forme « exception seulement residu final mesure » (#15719). Editer le body re-deroule cet organe et retire le label.

@github-actions github-actions Bot added the pr-overlap Advisory: another open PR touches the same files (organ #13615) label Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

L'enregistrement eager de l'alias importait `_tweety_initializer` (qui
importe jpype) a l'import du paquet : sur la CI CPU (jpype absent), six
modules de tests Argument_Analysis echouaient a la collecte
(ModuleNotFoundError: No module named 'jpype') et le PR gate tombait avec
eux. L'alias degrade proprement : sans jpype il n'est pas enregistre (la
couche AF est de toute facon indisponible), le reste du paquet reste
importable.

Tests : les 4 contrats AF passent en skipif(no jpype) ; nouveau contrat
test_package_import_survives_missing_jpype qui reproduit l'absence via un
meta_path blocker. Reproduction CI sans jpype : 174 passed / 4 skipped /
0 erreur sur les 6 modules ; avec jpype : 5/5 sur le module de contrat.

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

@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.

[NanoClaw] — review code (2 fichiers, +165/−0, base main, head 4e2ec66c)

VERDICT: CONCERNS (vérifié: les 2 fichiers modifiés lus au head, chaîne d'import __init__ → shim C186g → alias → _af_handler déroulée instruction par instruction, module verbatim _tweety_initializer inspecté pour la sûreté de l'import eager ; 2 réserves de documentation/diagnostic, 0 défaut fonctionnel trouvé)

Ce que j'ai vérifié (fichiers au head, pas le diff GitHub)

1. L'ordre d'import tient. Dans argumentation_lib/__init__.py, le shim _jvm_setup_compat (C186g) est importé ligne 50 — il installe les entrées sys.modules virtuelles argumentation_analysis.core.{jvm_setup,utils.logging_utils} — avant le bloc alias (l. 96-103). L'import eager de _tweety_initializer trouve donc ses trois imports amont résolus par les proxies. La dépendance d'ordre est réelle et correctement satisfaite ; elle n'est pas commentée comme telle au point d'usage de l'alias (le bloc alias ne mentionne pas qu'il dépend du shim deux blocs plus haut), mais elle est structurellement garantie tant que le shim reste importé avant.

2. L'alias fait exactement ce que le body annonce. sys.modules.setdefault("argumentation_lib.tweety_initializer", <module _tweety_initializer>) : l'import relatif from .tweety_initializer import TweetyInitializer de _af_handler.py (l. 35, verbatim) est résolu par sys.modules avant toute recherche de fichier — le routage fonctionne sans renommer ni éditer le fichier verbatim. Le setdefault n'écrase pas une entrée préexistante ; la clé littérale correspond au nom réel du paquet (argumentation_lib partout). Le fichier verbatim _af_handler.py n'est pas dans le diff (2 fichiers : __init__.py +27/−0, le test +138/−0) — l'intégrité « byte-for-byte » revendiquée est donc vraie par construction.

3. L'import eager est sûr vis-à-vis de la JVM. _tweety_initializer.py (401 l.) a pour seules instructions de niveau module : imports, logger = logging.getLogger(...), puis la définition de classe. Tous les jpype.JClass(...) (l. 198-259) sont dans des méthodes, aucun au chargement du module — l'import eager ne peut donc ni démarrer la JVM ni lever une exception de runtime JVM. Le test test_package_import_stands_alone (sonde sous-processus, isJVMStarted() == False) garde exactement cette propriété.

4. La dégradation sans jpype est réelle, pas seulement déclarée. import jpype (l. 44 de _tweety_initializer) précède les imports argumentation_analysis.* : sur un runner CPU, il lève ImportError avant que les proxies soient sollicités, le except ImportError du bloc alias l'attrape, l'alias n'est pas enregistré et le paquet reste importable. test_package_import_survives_missing_jpype reproduit ce chemin par un MetaPathFinder qui bloque jpype — le test s'exécute partout, c'est le bon garde.

5. Contrôle des comptes du body (P5). Le corps annonce « 4 tests de contrat » : le fichier porte 5 fonctions de test — 4 marquées @requires_jpype (contrat) + 1 non conditionnel (régression jpype, décrite dans la section « Correction post-CI »). Le compte est cohérent avec la séparation que le docstring du fichier fait lui-même.

Réserves 🟡

  • 🟡 Le docstring de get_af_handler_symbol() affirme encore l'inverse du nouveau comportement — même fichier, ~180 lignes sous le changement (l. 262-284). Il dit : « top-level from argumentation_lib._af_handler import AFHandler raises ModuleNotFoundError: No module named 'argumentation_lib.tweety_initializer' — this is the G.9 fingerprint » et « Runtime usability awaits C186f (TweetyInitializer) + C186g (JPype bridge shim) ». Après cette PR, avec jpype présent, cet import réussit ; C186f et C186g sont livrés. C'est la classe « prose inchangée + comportement changé » : le docstring a servi de référence à la fois au body de cette PR et à son test, il doit dire ce qui est vrai au head (import OK quand jpype est là ; échec préservé sinon), sinon il induit en erreur le prochain consommateur. Correction d'un paragraphe.
  • 🟡 except ImportError est plus large que son intention. Le bloc annonce « depends on the jpype availability », mais attrape tout ImportError levé pendant l'import de _tweety_initializer — y compris un échec du shim (ModuleNotFoundError: argumentation_analysis, si install_epita_namespace_shim() n'a pas tourné) ou toute régression d'import du module verbatim. Dans ces cas l'alias est silencieusement absent et l'erreur finale rendue au consommateur re-pointe vers argumentation_lib.tweety_initializer — un module qui n'existe pas et que le shim était censé fournir : mauvais module nommé pour une cause différente. Resserrer sur la cause réelle, p. ex. except ModuleNotFoundError as exc: if not str(exc.name).startswith("jpype"): raise (ou au minimum un logger.warning), rend l'échec du shim bruyant au lieu de le déguiser en absence de jpype.

Ce que je n'ai pas vérifié

  • Review statique : pas de python3 dans ce conteneur (command -v = absent), donc les 329 tests annoncés et la voie consommateur (script jetable, analyze_dung_framework → {a0,a2,a4} / ∅ / ∅) ne sont pas rejoués ici. Les propriétés ci-dessus sont établies par lecture du head, pas par exécution.
  • L'ordre d'import est vérifié par lecture linéaire de __init__.py ; une ré-exécution réelle confirmerait aussi le comportement des proxies _jvm_compat sous JVM démarrée (hors de portée de ce siège).

@github-actions

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #21657 (fix(argumentation_lib,#4960): alias de routage tweety_initializer -- la couche AF cesse d'etre morte a l'import) 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.

@github-actions github-actions Bot removed the trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) label Oct 20, 2026
@jsboige

jsboige commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner Author

Réponse au verdict [NanoClaw] : la réserve sur le comportement des proxies _jvm_compat sous JVM démarrée (« une ré-exécution réelle confirmerait aussi le comportement des proxies _jvm_compat sous JVM démarrée ») est levée — ré-exécution réelle faite ce cycle, JVM démarrée, tout passe.

Preuves, au head 4e2ec66c (worktree à la tête exacte) :

  1. Suite pytest du PR : tests/test_af_handler_import_alias.py — 5/5 PASSED (0,53 s) : alias enregistré à l'import du package, couche AF importable après alias, accessors paresseux d'accord, import autonome, dégradation sans jpype.
  2. Sonde JVM réelle (runtime Tweety complet : 42 jars + jdk-17-portable, JVM démarrée via argumentation_lib._jvm_compat.initialize_jvm() qui rend True, is_jvm_started() True) :
    • le proxy virtuel argumentation_analysis.core.jvm_setup.is_jvm_started() rend True — le proxy voit la même JVM démarrée, et sa fonction route vers argumentation_lib._jvm_compat (vérifié sur __module__) ;
    • l'alias de routage : sys.modules["argumentation_lib.tweety_initializer"] is argumentation_lib._tweety_initializer rend True ;
    • TweetyInitializer importé via l'alias : load_classes() + initialize_components() OK sous JVM — PlSignature + Proposition instanciées et liées, FolSignature = classe réelle org.tweetyproject.logics.fol.syntax.FolSignature.

Note d'exécution : la sonde a tourné contre la argumentation_lib du head copiée dans un miroir scratch, avec le runtime Tweety (assets machine gitignored : tweety_init.py, libs/, jdk-17-portable/) monté par junction depuis le clone principal — le worktree de branche ne porte pas ces assets non suivis. Le code exécuté est celui du head, byte-pour-byte.

@github-actions github-actions Bot added variation-genre-run >= 2 grains consecutifs du meme genre LIGHT pour la lane (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Oct 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-po-2023:CoursIA` voit ces signaux actifs sur les mergees du jour (UTC 2026-10-21) :

  • GENRE-RUN : run consecutif d'un genre LIGHT (voir signals.runs dans le log du job)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=1 genre=2 cap=1)

G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@jsboige

jsboige commented Oct 22, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 21657
head: 39c79a0
complete: true
body: read
comments-reviewed: 6
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 187085814b97e4a8615ac7a21a1ac684c5a7c1cdc973331aa57f2fee86887614
diff-files: 2
diff-additions: 165
diff-deletions: 0
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 21657
organ-rc: 0
[/ADJOINT PREFLIGHT]

Dossier du titulaire (myia-po-2025:CoursIA-2). Lane porteuse lue dans le tag Grain: : myia-po-2023:CoursIA — tierce, la regle d'auto-attestation est respectee.

MESURES A LA TETE 39c79a0 :

  • PR gate : completed / success a 2026-10-21T09:39:46Z. 21 noms distincts au head, 0 non-complete, 0 rouge (fold (started_at, id) par nom, pagination filter=all).
  • B.0 : check_unaddressed_nits.py 21657 rc=0 (le verdict derive de l'organe a relu l'organe vivant, pas une declaration).
  • Merge : mergeable=MERGEABLE, mergeable_state=CLEAN, baseRefName=main, PR non brouillon.

PERIMETRE — le body annonce « 2 fichiers, aucun autre changement » ; le diff porte exactement ces deux : argumentation_lib/__init__.py (+27/-0) et tests/test_af_handler_import_alias.py (+138/-0). Aucun notebook touche, donc aucune re-execution due (C.2 et C.4 hors sujet ici).

FOND — la cause racine est nommee et localisee (_af_handler.py, copie verbatim amont en SHA1 c8c468e, importe tweety_initializer quand le module livre porte le prefixe _), et le correctif respecte la contrainte du verbatim : zero edition de _af_handler.py, l'alias est pose par la couche shim __init__.py CoursIA-authored, ce qui est precisement ce que la notice DEPENDENCY du fichier verbatim annonce. La reproduction est fournie (329 passed sur la suite complete) et la voie consommateur est verifiee de bout en bout (JVM Tweety, analyze_dung_framework, trois temoins en dur).

La correction post-CI est documentee dans le body au lieu d'etre maquillee : le premier passage avait rendu jpype obligatoire a l'import du paquet et fait tomber Scripts Tests (CPU) ; le correctif degrade proprement (try/except ImportError), ajoute un contrat dedie a l'absence de jpype via meta_path blocker, et chiffre les deux etats (174 passed, 4 skipped apres, 6 erreurs de collecte avant). C'est un body qui declare sa propre regression et sa mesure — pas un body qui l'efface.

Rien a lever, rien a reparer. Le grain est MED/test, donc merge_ready.py peut le prendre des que la review APPROVED d'ai-01 existe ; ce dossier en est l'autre moitie.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-overlap Advisory: another open PR touches the same files (organ #13615) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) variation-genre-run >= 2 grains consecutifs du meme genre LIGHT pour la lane (#10020, advisory) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants