Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion MyIA.AI.Notebooks/QuantConnect/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ cloudpickle>=3.0.0
# - Requires Docker Desktop running
#
# Version Compatibility:
# - Python 3.11+ recommended
# - Python 3.11 recommended (canon #19181, aligne sur QuantConnect cloud)
# - Compatible with QuantConnect cloud (Python 3.11)
# - L'execution locale des carnets se fait en Python 3.13 (l'interpreteur
# de la flotte, qui ecrit ``language_info.version`` a chaque rejeu).
# Deux canons par design, pas un seul.
# - La table CANONICAL_LANGUAGE_TRANSITIONS du cliquet
# ``scripts/notebook_tools/check_kernel_drift.py`` accepte les
# transitions 3.10 -> 3.11 (migration historique vers QC Cloud),
# 3.11 -> 3.13 (convergence vers l'interpreteur local), le saut
# direct 3.10 -> 3.13 (cas fondateur #19181, PR #19163 : 3.10.11
# -> 3.13.3), et 3.12 -> 3.13 (anticipation de convergence, pas de
# carnet `python3` a 3.12 mesuré a l'instant -- ICT-47 sur main est
# a `py310-gpu` 3.12.13, kernelspec distinct de `python3`, donc hors
# scope). La direction inverse reste rouge.
# - NumPy < 2.0 for compatibility with some libraries
57 changes: 50 additions & 7 deletions scripts/notebook_tools/check_kernel_drift.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

- Kernel change: ``metadata.kernelspec.name`` or
``metadata.language_info.version`` differs at major.minor level
(Python 3.11 -> 3.13). Patch-only drift (3.13.3 -> 3.13.15) is NOT
flagged: the venv patch evolves under the canonical interpreter and
never changes repr() semantics (#17371). Outputs may format
``repr(np.float64(0.9999999999999999))`` instead
(Python 3.10.11 -> 3.13.3, 3.11 -> 3.13). Patch-only drift (3.13.3 ->
3.13.15) is NOT flagged: the venv patch evolves under the canonical
interpreter and never changes repr() semantics (#17371). Outputs may
format ``repr(np.float64(0.9999999999999999))`` instead
of ``[1.0, 1.0, ...]`` even when the cell computes the same values.
- Float format drift: NumPy 1.x prints ``[1.0, 1.0, 1.0]``; NumPy 2.x
prints ``[1.0, 0.9999999999999999, 1.0]``. The values are within
Expand Down Expand Up @@ -221,12 +221,55 @@ def diff_kernel(base_info, head_info):
# coordinateur 2026-09-26) : la derive va dans le sens du canon decide --
# ce n'est pas une regression, pas plus qu'une derive de patch (#17371).
# La DIRECTION porte l'acceptation : la transition inverse reste rouge.
# Portee au kernel .NET C# mesure dans le depot (kernelspec
# ``.net-csharp`` : 141 notebooks a 13.0, 7 a 12.0 au 2026-09-27) -- la
# classe fondatrice Python 3.11 -> 3.13 reste hors table.
# Portee mesuree au 2026-10-05 :
# - C# ``.net-csharp`` : 141 notebooks a 13.0, 7 a 12.0 (#17679).
# - Python ``python3`` (serie QC/Python) : 11 versions heterogenes
# (3.8.10, 3.9.0, 3.10.0, 3.10.11, 3.10.19, 3.11.0, 3.11.9, 3.11.14,
# 3.11.15, 3.13.3, 3.13.7, 3.13.12, 3.13.14) ; 60 carnets ``python3`` + 2
# ``conda-torch``.
# - Decision duale sur le canon (coord. 2026-10-05T03:43:46Z, DM
# msg-20261005T034346-qyldsl) : **deux canons**, pas un seul --
# (a) **canon des algorithmes deployes sur QC Cloud = Python 3.11**,
# documente dans ``MyIA.AI.Notebooks/QuantConnect/requirements.txt`` ;
# (b) **canon de l'execution locale des carnets = Python 3.13**, qui est
# l'interpreteur de la flotte -- c'est lui qui ecrit
# ``language_info.version`` a chaque rejeu.
# Les deux roles sont separes par design ; la migration historique
# ``3.10 -> 3.11`` reste couverte, et la convergence future
# ``3.11 -> 3.13`` aussi, plus le saut direct ``3.10 -> 3.13``
# (cas fondateur de #19181, PR #19163 : 3.10.11 -> 3.13.3).
# Le saut ``3.12 -> 3.13`` est couvert : ICT-47 (PainAxisDistillation)
# sur main est a ``language_info.version = 3.12.13`` (mesure directe
# sur le carnet, 2026-10-05), mais son kernelspec est ``py310-gpu``
# (distinct de ``python3``), donc le tuple ``("python3", "3.12", "3.13")``
# ne s'applique pas a ce carnet -- la table exige le meme nom de
# kernel entre base et tete. L'entree anticipe la convergence vers
# le canon pour un futur carnet ``python3`` a 3.12.x ; aucun carnet
# de cette forme n'est encore mesuré sur main. Le saut
# ``3.11 -> 3.12`` reste implicite (3.12 = release courante de
# plusieurs carnets), mais n'est pas ajoute en l'absence d'un carnet
# de reference ``python3`` qui le pratique.
# Les sauts ``3.8 -> 3.13`` et ``3.9 -> 3.13`` sont **exclus** : la
# serie ICT (#5635, ICT-24) reste sur ``requires-python >=3.9,<3.10``
# (contrainte ``pyphi==1.2.0``, mesure #19160), et le cliquet n'a
# pas de scope par chemin/série -- ajouter ces transitions ferait
# passer vert un carnet ICT rejoue par erreur sous 3.13 (reserve
# Hermes PRR_kwDOH2Odns8AAAABQnPfEQ, 2026-10-05). Les 2 rescapes
# ``3.8.10`` et ``3.9.0`` (1 carnet chacun, mesure body) sont
# traites au cas par cas.
# La transition inverse (3.13 -> 3.12, 3.13 -> 3.11, 3.11 -> 3.10,
# 3.13 -> 3.10) reste rouge.
CANONICAL_LANGUAGE_TRANSITIONS = {
(".net-csharp", "12.0", "13.0"):
"C# 12.0 -> 13.0 : convergence vers le canon C# 13.0 (#17679)",
("python3", "3.10", "3.11"):
"Python 3.10 -> 3.11 : convergence vers le canon QC/Python 3.11 (#19181)",
("python3", "3.11", "3.13"):
"Python 3.11 -> 3.13 : convergence vers le canon d'execution 3.13 (#19181)",
("python3", "3.10", "3.13"):
"Python 3.10 -> 3.13 : convergence directe vers le canon d'execution 3.13 (#19181, cas fondateur)",
("python3", "3.12", "3.13"):
"Python 3.12 -> 3.13 : convergence vers le canon d'execution 3.13 (#19181, anticipation -- pas de carnet `python3` a 3.12 mesure)",
}


Expand Down
120 changes: 117 additions & 3 deletions scripts/notebook_tools/tests/test_check_kernel_drift.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,125 @@ def test_canonical_transition_kernelspec_change_refused():
assert ckd.accepted_canonical_transition(a, b) is False


def test_canonical_transition_python_minor_stays_out():
# La classe fondatrice (Python 3.11 -> 3.13) reste hors table : la
# table est scoped au kernel, pas au couple de numeros.
# --- #19181 : table d'acceptation canon Python (QC/Python) -----------------
# Mesure du 2026-10-05 sur la serie QC/Python : 11 versions heterogenes
# (3.8.10 a 3.13.14) ; 60 carnets ``python3`` + 2 ``conda-torch``.
# Decision duale coord. (2026-10-05T03:43:46Z, DM
# msg-20261005T034346-qyldsl) :
# - canon des algorithmes deployes sur QC Cloud = Python 3.11
# (documented in ``MyIA.AI.Notebooks/QuantConnect/requirements.txt``) ;
# - canon de l'execution locale des carnets = Python 3.13 (l'interpreteur
# de la flotte qui ecrit ``language_info.version`` a chaque rejeu).
# Transitions acceptees en direction du canon : 3.10 -> 3.11 (historique
# QC Cloud), 3.11 -> 3.13 (convergence locale), 3.10 -> 3.13 (cas
# fondateur de #19181, PR #19163 : 3.10.11 -> 3.13.3), et 3.12 -> 3.13
# (anticipation de convergence ; ICT-47 sur main est a `py310-gpu`
# 3.12.13, kernelspec distinct de `python3`, donc hors scope de ce
# tuple -- l'entree anticipe un futur carnet `python3` a 3.12). La
# direction inverse reste rouge.


def test_canonical_transition_python_311_to_313_accepted():
# Positif 1 : la convergence vers Python 3.13 (canon d'execution) est
# couverte.
a = {"language_version": "3.11.16", "kernelspec_name": "python3"}
b = {"language_version": "3.13.3", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is True
# la derive brute existe bien -- c'est la table qui l'accepte.
assert ckd.diff_kernel(a, b)


def test_canonical_transition_python_310_to_311_accepted():
# Positif 2 : la migration historique vers le canon QC Cloud 3.11 est
# couverte.
a = {"language_version": "3.10.19", "kernelspec_name": "python3"}
b = {"language_version": "3.11.9", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is True


def test_canonical_transition_python_31011_to_3133_accepted():
# Positif 3 (cas fondateur #19181, PR #19163) : la convergence directe
# 3.10.11 -> 3.13.3 est couverte. La flotte rejette les carnets en
# 3.13 (interpreteur local), donc cette transition est le passage
# reel ; les transitions via 3.11 sont possibles mais ne se
# composent pas (cle tuple exact).
a = {"language_version": "3.10.11", "kernelspec_name": "python3"}
b = {"language_version": "3.13.3", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is True


def test_canonical_transition_python_38_to_313_refused():
# Negatif 5 : 3.8 -> 3.13 reste rouge par construction. Le saut 3.8
# n'est pas couvert par la table (serie ICT pinnée <3.10, pyphi==1.2.0,
# mesure #19160 ; sans scope par chemin/série, ajouter la transition
# ferait passer vert un carnet ICT rejoue par erreur -- reserve Hermes
# PRR_kwDOH2Odns8AAAABQnPfEQ, 2026-10-05). Les 2 rescapes 3.8.10/3.9.0
# sont traites au cas par cas.
a = {"language_version": "3.8.10", "kernelspec_name": "python3"}
b = {"language_version": "3.13.3", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is False


def test_canonical_transition_python_39_to_313_refused():
# Negatif 6 : 3.9 -> 3.13 reste rouge (meme raison que 3.8).
a = {"language_version": "3.9.0", "kernelspec_name": "python3"}
b = {"language_version": "3.13.3", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is False


def test_canonical_transition_python_313_to_311_refused():
# Negatif 1 : la direction inverse est une regression du canon.
a = {"language_version": "3.13.3", "kernelspec_name": "python3"}
b = {"language_version": "3.11.16", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is False


def test_canonical_transition_python_311_to_310_refused():
# Negatif 2 : retombada sur 3.10 apres adoption du canon 3.11.
a = {"language_version": "3.11.9", "kernelspec_name": "python3"}
b = {"language_version": "3.10.19", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is False


def test_canonical_transition_python_313_to_38_refused():
# Negatif 3 : retomber de 3.13 a 3.8 reste rouge, meme si 3.8 -> 3.13
# est accepte dans l'autre sens.
a = {"language_version": "3.13.3", "kernelspec_name": "python3"}
b = {"language_version": "3.8.10", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is False


def test_canonical_transition_python_31213_to_3133_accepted():
# Positif : la transition 3.12 -> 3.13 est couverte. Anticipation :
# aucun carnet main n'exerce aujourd'hui le tuple (`python3`, `3.12`,
# `3.13`) — le seul carnet a 3.12 mesure est ICT-47
# (PainAxisDistillation), dont le kernelspec est `py310-gpu` (distinct
# de `python3`), donc hors scope de ce tuple (le cliquet exige le meme
# nom de kernel entre base et tete). L'entree est ajoutee pour
# preparer la convergence d'un futur carnet `python3` a 3.12.x. Le
# temoin effectif du test est le tuple synthetique ci-dessous, pas
# ICT-47. Ajout a la demande du coordinateur (commentaire 5988053521,
# 2026-10-05T04:22Z), oubli du dispatch initial qui ne listait pas
# 3.12 dans les couverts.
a = {"language_version": "3.12.13", "kernelspec_name": "python3"}
b = {"language_version": "3.13.3", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is True


def test_canonical_transition_python_313_to_312_refused():
# Negatif : la direction inverse 3.13 -> 3.12 reste rouge (n'a pas
# ete ajoutee a la table ; convention : la table n'accepte que les
# convergences vers le canon, pas la descente).
a = {"language_version": "3.13.3", "kernelspec_name": "python3"}
b = {"language_version": "3.12.13", "kernelspec_name": "python3"}
assert ckd.accepted_canonical_transition(a, b) is False


def test_canonical_transition_python_kernelspec_change_refused():
# Negatif 4 : un changement de kernelspec.name reste rouge, meme avec
# des versions couvertes par la table.
a = {"language_version": "3.11.9", "kernelspec_name": "python3"}
b = {"language_version": "3.13.3", "kernelspec_name": "python311"}
assert ckd.accepted_canonical_transition(a, b) is False


Expand Down
Loading