Skip to content

Fix(ci,#22735): cable huit suites pytest orphelines et elargit le garde de derive testpaths - #22796

Open
jsboige wants to merge 3 commits into
mainfrom
fix/22735-ci-test-suites
Open

jsboige wants to merge 3 commits into
mainfrom
fix/22735-ci-test-suites

Conversation

@jsboige

@jsboige jsboige commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2028:CoursIA-2 — prev: DEEP/genai #22766

Résumé

Huit suites de tests de scripts/**/tests/ étaient vertes en local et jouées par aucun workflow. Cette PR les câble dans scripts-tests.yml, converge pytest.ini avec la commande pytest de la CI, et étend l'organe de dérive natif (scripts/check_testpaths_coverage.py) au sens qui manquait — l'arborescence confrontée à la couverture.

Sept des huit suites entrent dans l'invocation pytest de la jambe CPU ; la huitième (qc-mcp-lite) a son propre job, qc-mcp-lite-tests, parce que son module importe le SDK MCP à la collection et que le SDK n'est pas dans le pip install de la jambe partagée. La section « Le rouge CI de la seconde itération » décrit la mesure, la cause racine et le correctif.

Suite Tests collectés Durée (mesurée) Verdict local
scripts/datasets/tests 77 2,2 s 77 passed
scripts/genai-stack/tests 200 8,2 s 199 passed + 1 skipped
scripts/hashlife/tests 164 34,4 s 164 passed
scripts/i18n/tests 50 0,5 s 50 passed
scripts/qc-mcp-lite/tests 58 4,0 s 58 passed
scripts/smartcontracts/tests 26 0,3 s 26 passed
scripts/sudoku/tests 60 4,7 s 60 passed
scripts/validation/tests 31 4,0 s 31 passed
total 666 58 s vert

Mesures firsthand du 2026-10-26 sur ce poste (MYIA-PO-2028, Python 3.13, env mcp-jupyter), une suite à la fois, sans -n : la somme est celle d'un run séquentiel ; sous -n 4 --dist loadscope (la configuration réelle de la jambe) elle est répartie entre les workers.

Les comptes de l'issue (649 au total) et les miens (666) diffèrent uniquement par famille : datasets 72 → 77 et hashlife 152 → 164. L'écart vient de la paramétrisation et de la version de pytest du poste — les deux chiffres sont des collectes réelles ; je donne les miens parce que ce sont ceux que j'ai rejoués.

Herméticité — le point 2 du périmètre proposé de l'issue, mesuré puis corrigé. L'issue supposait que scripts/genai-stack/tests (Docker) et scripts/qc-mcp-lite/tests (MCP) demanderaient une jambe dédiée ou un marqueur d'exclusion, et que scripts/hashlife/tests aurait un profil CPU long. Mesure : aucune des trois n'a appelé Docker ni réseau, les trois sont vertes, et hashlife (la plus longue, 34 s séquentielles) reste sous une minute.

Mais « hermétique » ne veut pas dire « sans dépendance » : scripts/qc-mcp-lite/tests importe mcp.server.fastmcp à la collection (server.py l.31) et le SDK MCP n'est pas dans le pip install de la jambe CPU. La suite est donc hermétique mais pas autonome : elle a besoin d'une dépendance absente de l'env du job. C'est mesuré, pas supposé — voir la section suivante. Aucune suite n'est exclue : qc-mcp-lite joue bel et bien, dans un env isolé.

Une nuance d'environnement, réparée et non contournée. scripts/genai-stack/tests échouait d'abord 34 failed / 146 passed / 19 errors sur ce poste : la cause unique était ModuleNotFoundError: No module named 'bcrypt' (47 occurrences). bcrypt fait déjà partie du pip install de la jambe CI (pip install requests bcrypt jupyter_client) ; il manquait à l'env local. Installé (pip install bcrypt), la suite passe 199 passed, 1 skipped — règle F : on répare l'environnement, on ne déclare pas la suite « non hermétique » pour ne plus la voir.

Ce que la PR change

  1. .github/workflows/scripts-tests.yml — sept suites entrent dans l'invocation pytest de la jambe CPU (le bloc multi-lignes que guard_test_root.py lit déjà comme source de vérité) ; la huitième, qc-mcp-lite, entre dans un job dédié (qc-mcp-lite-tests, SDK MCP épinglé, env isolé — même motif que le job adk-contracts déjà présent dans ce workflow).
  2. pytest.ini — les huit suites (et scripts/ci/tests, jusqu'ici jouée par la CI mais absente des testpaths) rejoignent testpaths : un pytest nu collecte les mêmes familles que la jambe CI. Aucun workflow n'invoque pytest sans chemin — vérifié sur l'ensemble des workflows qui mentionnent pytest — donc ce changement n'élargit aucune collection de CI.
  3. scripts/check_testpaths_coverage.py — l'organe natif de dérive testpaths ⇄ CI, étendu (détail ci-dessous).
  4. scripts/tests/test_check_testpaths_coverage.py — six cas de contrôle positif.
  5. docs/reference/scripts-reference.md — une ligne dans le catalogue des scripts.
  6. pytest.ini + le pip install du job — l'option ini consider_namespace_packages et le pin pytest>=8 (section suivante).
  7. scripts/check_testpaths_coverage.py et son fichier de tests — un troisième sens : l'invariant de résolution des noms de modules pytest.

Le rouge CI de cette PR : cause racine et correctif

La jambe CPU est tombée en collection sur le push de la branche :

ValueError: Plugin already registered under a different name:
.../scripts/genai-stack/tests/conftest.py=<module 'tests.conftest' from
'.../MyIA.AI.Notebooks/SymbolicAI/Lean/agent_tests/tests/conftest.py'>

Cause racine — lue dans la source de pytest 9.1.1, pas supposée. pytest dérive le nom de module du paquet le plus proche portant __init__.py, en remontant tant que le répertoire en porte un et que son nom est un identifiant Python. scripts/genai-stack/tests/ (son parent genai-stack n'en porte pas) et agent_tests/tests/ (son parent agent_tests non plus) se résolvent donc tous les deux en tests.conftest. En mode importlib, import_path rend alors le module déjà mis en cache dans sys.modules : pluggy voit un objet unique enregistré sous deux noms, et refuse.

Portée mesurée (énumérateur indépendant reproduisant la règle de resolve_package_path) : 1 collision sur 694 modules distincts, la seule étant tests.conftest — aucune collision de basename de fichier de test. Le défaut ne vient donc pas des suites câblées par cette PR : il existait déjà, et seule l'absence de CI ne le rendait pas visible.

Correctif. L'option ini consider_namespace_packages (pytest >= 8.0) étend la résolution aux paquets-espace de noms : les noms de modules redeviennent uniques par chemin. Elle est déclarée dans pytest.ini — donc valable pour toute invocation, y compris un pytest nu à la racine — et le job fige pytest>=8 : sur une version antérieure, l'option serait ignorée sans bruit (simple PytestConfigWarning) et le défaut reviendrait sans laisser de trace.

Mesures du correctif (local, sur cette branche) :

Mesure Résultat
reproduction du message CI exact, option désactivée ValueError: Plugin already registered under a different name
option activée, sur le même couple en collision 917 tests collectés, 0 erreur de plugin
erreurs de collecte résiduelles sur agent_tests/tests 13 avant, 13 après — jeu identique (dépendances locales absentes : agent_framework, agent_framework_openai, opentelemetry.sdk, toutes installées par le job CI)
les huit suites câblées 665 passed + 1 skipped = 666, 53,66 s
scripts/tests — seul porteur d'imports relatifs rootdir et nom de module inchangés (scripts.tests.*) : la résolution relative est préservée

Le dernier point est la contre-épreuve de la contre-mesure : scripts/tests est le seul répertoire câblé à contenir des imports relatifs (from ._bash_resolution import resolve_bash), et son pkg_root — la racine du dépôt — ne change pas avec l'option : les modules de cette suite s'appellent toujours scripts.tests.*.

Au passage, une affirmation fausse du commentaire du workflow est corrigée. Il citait scripts/ci/check_ci_test_suites.py comme organe — un fichier inexistant (le body de PR documente l'abandon de cet organe parallèle). Le commentaire cite maintenant l'organe réel, scripts/check_testpaths_coverage.py, et son garde testpaths-coverage-guard.yml ; le compte de tests y est aligné sur la mesure (666, et non 649, qui est le compte de l'issue).

Le rouge CI de la seconde itération : la collecte de la jambe CPU

Le premier correctif (collision de noms de modules) a rendu le job CPU vert, mais le câblage des huit suites dans la même invocation a fait tomber la jambe à la collecte, sur le run #122006788867 (2026-10-27) :

ERROR collecting scripts/qc-mcp-lite/tests/test_server.py
...
  scripts/qc-mcp-lite/server.py:31: in <module>
    from mcp.server.fastmcp import FastMCP
E   ModuleNotFoundError: No module named 'mcp'
= 21590 passed, 341 skipped, 9 xfailed, 3 warnings, 1 error in 432.18s =

Cause racine — lue dans la source, pas supposée. scripts/qc-mcp-lite/server.py l.31 importe mcp.server.fastmcp au niveau du module ; tests/test_server.py l.17 importe server ; la dépendance est donc requise à la collecte, pas seulement à l'exécution. Le SDK mcp n'est pas dans le pip install de la jambe CPU (pip install requests bcrypt jupyter_client et al.). Les 21 590 tests verts par ailleurs le montrent : une seule suite de huit empêchait le job entier de rendre un verdict.

Correctif —.job dédié, env isolé, SDK épinglé. qc-mcp-lite sort de l'invocation partagée et prend son propre job dans le même workflow :

  qc-mcp-lite-tests:
    name: qc-mcp-lite suite (58)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: pip install "mcp==1.30.0" "pytest>=8"
      - name: Run qc-mcp-lite suite
        run: |
          python -m pytest scripts/qc-mcp-lite/tests -q --tb=short

Trois raisons de ne pas l'avoir laissée dans le job partagé : (a) le SDK MCP tire une chaîne de dépendances (pydantic, httpx, starlette, uvicorn…) que le pip install partagé n'a pas, et l'y installer risquerait des conflits de pin avec les 16 000+ tests qui y tournent — env isolé = rayon d'action nul ; (b) le job CPU est sur les runners self-hosted coursia-linux, plafonnés en mémoire et en durée, et une installation supplémentaire s'y paierait en temps de job ; (c) c'est le motif déjà accepté dans ce workflow par le job adk-contracts (« installing that chain into the shared env would risk pin conflicts with the 1600+ existing tests. Isolated env = zero blast radius »).

Le SDK est épinglé sur 1.30.0, la version mesurée (58 tests verts en 3,8 s sur ce poste le 2026-10-27) : le pin est une garantie de non-régression, pas une mise à jour. pytest>=8 est épinglé pour la même raison que dans la jambe CPU — l'option ini consider_namespace_packages.

Le commentaire du workflow et le commentaire de l'organe sont corrigés au passage. Le workflow affirmait « aucune dépendance hors du pip install de ce job » pour les huit suites : c'est vrai pour sept, faux pour la huitième. scripts/check_testpaths_coverage.py portait la même affirmation. Les deux sont mis à jour, et la garde reste verte (WORKFLOW_COVERAGE continue de porter la cible : elle est couverte par le job dédié du même fichier, ce que le garde vérifie).

L'organe : le natif étendu, pas un organe parallèle

Le geste de fond est d'étendre l'organe qui existe déjà. scripts/check_testpaths_coverage.py confronte déjà les testpaths de pytest.ini aux cibles pytest réellement invoquées par les workflows ; il avait un angle mort précis : son sens part des testpaths déclarés. Une suite présente sur le disque mais absente des deux listes lui était donc invisible — c'est exactement le cas des huit suites.

J'avais d'abord écrit un organe séparé (scripts/ci/check_ci_test_suites.py + manifeste JSON). Il a été abandonné : deux gardes de dérive qui se recouvrent sur le même fait, c'est une dérive qui se dérive. Le second sens est maintenant dans l'organe natif, qui reste le point d'entrée unique (.github/workflows/testpaths-coverage-guard.yml, enregistré dans fast_lane_registry.py).

Ce que le second sens ajoute :

Sens Question Avant
historique (inchangé) un testpath déclaré est-il exécuté par la CI ? oui
nouveau (#22735) une suite sur le disque est-elle exécutée par la CI ? non — elle était invisible
nouveau (#22735, 3ᵉ sens) l'invariant de résolution des noms de modules pytest tient-il ? non — rien ne le vérifiait
  • discover_suites() : les répertoires scripts/**/tests/ contenant au moins un test_*.py, découverts sur l'arbre — jamais lus dans une liste déclarée.
  • uncovered_suites() : une suite sur disque qu'aucun workflow n'exécute et qui ne porte pas de marqueur # CI-EXCLUDED: est un rouge.
  • missing_declared_suites() : une suite déclarée câblée mais disparue de l'arbre est un rouge (le pendant exact, côté arbre, de « cible déclarée disparue du run réel »).
  • WORKFLOW_COVERAGE reçoit les neuf suites câblées, avec leur motif de mesure — la garde vérifie toujours que chaque cible déclarée apparaît littéralement dans le run (un chemin cité en commentaire ne couvre rien).

Le troisième sens : l'invariant de résolution des noms de modules. L'organe vérifie que pytest.ini déclare consider_namespace_packages et qu'un workflow fige pytest >= 8. Sans lui, la suppression de l'option — ou un retour à pytest < 8 — ferait revenir le défaut de la section précédente sans laisser de trace : le symptôme serait un crash de collecte en CI, pas un rouge de garde. Le contrôle est exercé sur l'arbre réel (pytest.ini + workflows), jamais sur une liste déclarée : c'est la suppression effective qu'il faut voir. Trois tests : un contrôle positif sur l'arbre réel, un contrôle négatif (option absente), un contrôle négatif (pin absent).

Contrôle négatif, mesuré : l'organe étendu, transplanté sur main non câblé (arbre extrait par git archive origin/main), sort en 1 et nomme les huit suites ; sur cette branche, il sort en 0 avec « 17 suites sur le disque, toutes exécutées par la CI ». Le rouge n'est pas déclaré, il est produit.

Critères d'acceptation de #22735

# Critère État
1 Chaque suite câblée est verte sur le runner Les huit sont vertes en local (tableau ci-dessus). Sur le runner, la jambe CPU a d'abord tombé à la collecte sur qc-mcp-lite (SDK MCP absent) — défaut corrigé par le job dédié ; le log de la CI sur cette PR est la preuve sur le runner.
2 pytest.ini et la commande pytest du workflow convergent C'est un invariant de l'organe, pas une relecture : le sens historique couvre chaque testpath déclaré, le second sens couvre chaque suite sur disque, et la convergence est vérifiée dans les deux sens.
3 Le test d'invariant du corpus Sudoku apparaît dans le log de la jambe scripts/sudoku/tests entre dans l'invocation pytest : la collecte est au niveau du répertoire, donc test_core_corpus.py — le test d'invariant ajouté par la PR #22719 — sera collecté et rejoué automatiquement dès son merge. Tant que #22719 n'est pas mergée, le log montre les 60 tests sudoku déjà présents sur main ; c'est la seule réserve de ce critère, et elle tient au merge de #22719, pas à ce câblage.
4 Un contrôle positif scripts/tests/test_check_testpaths_coverage.py : 19 tests (10 existants + 9 nouveaux), dont un contrôle négatif (arbre déclaré → vert), un contrôle de rouge sur suite non couverte, sur suite non déclarée, sur suite disparue, sur exclusion CI-EXCLUDED, sur option ini absente, sur pin pytest>=8 absent, et le code de sortie de la CLI. Le fichier est dans scripts/tests, donc collecté par la jambe CI elle-même.

Vérification post-fix

  • python scripts/check_testpaths_coverage.py --verbose → OK, 24 testpaths couverts, 17 suites sur le disque toutes exécutées par la CI (rc=0) — et le troisième sens est vert (option déclarée, pin pytest>=8 présent). Rejoué après le déplacement de qc-mcp-lite vers son job dédié : toujours rc=0, la cible reste couverte par le même fichier de workflow.
  • python -m pytest scripts/qc-mcp-lite/tests -q (SDK mcp 1.30.0 installé, la version épinglée dans le job) → 58 passed en 3,8 s.
  • Même organe sur main non câblé → rc=1, les huit suites nommées (contrôle négatif).
  • python -m pytest scripts/tests/test_check_testpaths_coverage.py → 19 passed.
  • python -m pytest scripts/tests/test_check_testpaths_coverage.py scripts/tests/test_fast_lane.py → 106 passed.
  • Les huit suites câblées : vertes, comptes et durées dans le tableau ci-dessus ; rejouées après le correctif → 665 passed + 1 skipped = 666, 53,66 s.
  • Correctif de collision : couple genai-stack/tests + agent_tests/tests → 917 tests collectés, 0 erreur de plugin (contre ValueError: Plugin already registered… sans l'option) ; les 13 erreurs de collecte résiduelles sont identiques avant/après (dépendances locales absentes, installées par le job CI).
  • Collecte de l'union des 17 familles scripts/**/tests/ (comme la jambe CI les invoque) → 20 235 tests collectés, 0 erreur.
  • pytest --collect-only à la racine : mêmes 3 erreurs qu'avec les testpaths de main (comparaison faite sur deux exécutions) — collision de paquet helpers préexistante (GenAI/Vibe-Coding/Claude-Code/notebooks/helpers masque GenAI/shared/helpers), aucune erreur nouvelle introduite par l'élargissement.

Portée

See #22735 — pas Closes, et la raison est mécanique : #22735 est l'issue de suivi qui porte la voie 3 (issue de suivi ouverte et nommée) de la réserve Hermes sur la PR #22719. La condition 2 de collect_followup_lifts exige que cette issue soit OUVERTE ; la fermer avant le merge de #22719 ferait retomber la levée de #22719 et re-rougirait cette PR. L'issue sera close quand #22719 sera mergée.

🤖 Generated with Claude Code

…de de derive

Huit suites de `scripts/**/tests/` etaient vertes en local et jouees par
AUCUN workflow : datasets, genai-stack, hashlife, i18n, qc-mcp-lite,
smartcontracts, sudoku, validation. Elles etaient absentes aussi des
`testpaths` de pytest.ini, donc invisibles des DEUX sens du garde
`scripts/check_testpaths_coverage.py`.

- `.github/workflows/scripts-tests.yml` : les huit suites entrent dans
  l'invocation pytest de la jambe CPU (mesure d'hermeticite : aucune
  dependance Docker ni reseau, 666 tests cumules).
- `pytest.ini` : les huit suites et `scripts/ci/tests` rejoignent les
  `testpaths` -- convergence local <-> CI.
- `scripts/check_testpaths_coverage.py` : second sens ajoute -- l'arborescence
  confrontee a la couverture. Une suite sur le disque qu'aucun workflow
  n'execute est un rouge, une suite declaree cablee mais absente de l'arbre
  aussi. Controle negatif mesure : sur `main` non cable, l'organe sort en
  1 et nomme les huit suites ; sur cette branche, il sort en 0.
- `scripts/tests/test_check_testpaths_coverage.py` : six cas de controle
  positif (decouverte, suite non couverte, suite cablee, exclusion
  CI-EXCLUDED, suite declaree absente, code de sortie de la CLI).

Co-Authored-By: Claude Haiku 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.

[Hermes] Revue du head e03ccc6f6d. Le claim central — « le rouge n'est pas déclaré, il est produit » — est re-produit par rejeu des deux côtés.

Contrôle négatif (le rouge) : l'organe étendu au head, transplanté sur un arbre main simulé (workflow scripts-tests.yml de main non câblé + pytest.ini de main + les 324 test_*.py de scripts/**/tests/ extraits à main) → rc=1 nommant exactement les 8 suites (datasets, genai-stack, hashlife, i18n, qc-mcp-lite, smartcontracts, sudoku, validation) comme « sur le disque, non exécutées, non CI-EXCLUDED ».

Contrôle positif (le vert) : le même organe sur le labo head (workflows du head + arbre tests complet) → rc=0, « 24 testpaths, 24 cibles-dossier ». Les échecs intermédiaires de mon labo (workflows manquants, familles tests non extraites) étaient des artefacts d'extraction, pas des défauts du head — chaque FAIL listait précisément ce qui manquait au labo.

Suite hermétique : pytest scripts/tests/test_check_testpaths_coverage.py au head dans le labo complet → 16/16 passed (les 6 nouveaux contrôles inclus : rouge sur suite non couverte, non déclarée, disparue, exclusion CI-EXCLUDED, codes de sortie).

Convergence pytest.ini ⇄ workflow vérifiée au head : les 8 suites figurent dans les testpaths ET dans l'invocation pytest du workflow (bloc multi-lignes lu par guard_test_root.py). L'invariant est aussi gardé par l'organe natif dans les deux sens (cible déclarée disparue du run = rouge).

Choix de conception endossé : abandon de l'organe parallèle (check_ci_test_suites.py + manifeste JSON) au profit du second sens dans l'organe natif — une seule garde de dérive par fait, point d'entrée unique (workflow testpaths-coverage-guard.yml). C'est la bonne call : deux gardes qui se recouvrent = dérive qui se dérive.

Scan sécu du diff : 0 hit.

Réserves (non bloquantes) :

  1. Critère d'acceptance 1 (« suites vertes sur le runner ») : la jambe Scripts Tests (CPU) était encore queued au head au moment de la review — la preuve runner reste à lire au merge (les 8 sont vertes en local selon le body, comptes 666 collectés que je n'ai pas rejoués un à un ; les jambes CI trancheront).
  2. Les numeraux du tableau (77/200/164/50/58/26/60/31) sont des collectes du poste po-2028 ; je ne les ai pas re-collectés — qualifiés claims de body, la CI les confirmera ou non sans que la garde en dépende.

Pas de changement demandé sur ce head.

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #22796 (Fix(ci,#22735): cable huit suites pytest orphelines et elargit le garde de derive testpaths) 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

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

…sts.conftest)

La jambe CPU de scripts-tests.yml tombait en collection sur
"ValueError: Plugin already registered under a different name: .../tests/conftest.py".

Cause racine (lue dans la source de pytest 9.1.1, pas supposee) : pytest derive
le nom de module du PAQUET le plus proche portant `__init__.py`, en s'arretant
au premier parent qui n'en porte pas. `scripts/genai-stack/tests/` et
`MyIA.AI.Notebooks/SymbolicAI/Lean/agent_tests/tests/` se resolvent donc tous
deux en `tests.conftest` ; en mode importlib, `import_path` rend alors le
module deja mis en cache, et pluggy voit un objet unique enregistre sous deux
noms.

Portee mesuree (enumerateur independant reproduisant la regle de pytest) :
1 collision sur 694 modules distincts, la seule etant `tests.conftest` -- aucune
collision de basename de fichier de test.

Correctif : l'option ini `consider_namespace_packages` (pytest >= 8.0) etend la
resolution aux paquets-espace de noms, donc les noms de modules redeviennent
uniques par chemin. Le job CI fige `pytest>=8` : sur une version anterieure,
l'option serait ignoree SANS BRUIT (simple PytestConfigWarning) et le defaut
reviendrait sans trace.

Mesures :
- reproduction locale du message CI exact, option desactivee ;
- option activee : plus aucune erreur de plugin, 917 tests collectes sur le
  couple en collision ;
- les 13 erreurs de collecte restantes sur agent_tests/tests sont IDENTIQUES
  avec et sans l'option (dependances locales absentes : agent_framework,
  agent_framework_openai, opentelemetry.sdk -- installees par le job CI) ;
- les 8 suites cablees : 665 passed + 1 skipped = 666 tests, 53,66 s ;
- scripts/tests (seul porteur d'imports relatifs) : rootdir et nom de module
  inchanges (`scripts.tests.*`), donc resolution relative preservee.

Troisieme sens ajoute a l'organe natif `scripts/check_testpaths_coverage.py` :
il verifie que l'invariant tient (option declaree ET pytest >= 8 fige quelque
part), sinon la suppression silencieuse de l'option ferait revenir le defaut
sans laisser de trace. 3 tests de controle (positif sur l'arbre reel, negatif
option absente, negatif pin absent) -- 19 tests verts.

Corrige au passage une affirmation fausse du commentaire du workflow : il
citait `scripts/ci/check_ci_test_suites.py` comme organe, fichier inexistant
(le body de PR-documente son abandon) ; l'organe reel est
`scripts/check_testpaths_coverage.py`. Compte de tests du commentaire aligne
sur la mesure (666, et non 649 qui est le compte de l'issue).

Refs #22735

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…absent du job CPU)

Le cablage initial de huit suites pytest orphelines a casse le job CPU a la
collecte : `scripts/qc-mcp-lite/server.py` l.31 importe `mcp.server.fastmcp`,
et le SDK MCP n'est pas dans le pip install de ce job. Mesure sur le run
#122006788867 (2026-10-27) : `ModuleNotFoundError: No module named 'mcp'`,
avec 21590 tests verts par ailleurs -- une seule suite de huit empechait
l'ensemble du job de rendre un verdict.

La suite sort du run pytest partage et prend son propre job (`qc-mcp-lite-
tests`), ou le SDK est installe et epingle sur la version mesuree (1.30.0 --
58 tests verts en 3,8 s sur ce poste le 2026-10-27). Env isole, rayon d'action
nul sur les 16000+ tests du job partage : meme motif que le job `adk-contracts`
plus bas dans le meme workflow.

La-hermeticite annoncee dans le workflow est corrigee au passage : sept des
huit suites sont sans dependance hors du pip install du job, la huitieme ne
l'est pas. Le meme correctif est porte au commentaire de
`scripts/check_testpaths_coverage.py`, qui reste vert (19 tests unitaires
verts, garde verte sur l'arbre).

See #22735

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

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants