Skip to content

fix(notebooks,#19967): ICT-24 Gate 24 -- tirage reproductible (SETS.index, plus hash(s)) - #19991

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/19967-gate24-hash-seed
Oct 9, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/19967-gate24-hash-seed

Conversation

@jsboige

@jsboige jsboige commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Grain: DEEP/notebook-python — lane myia-po-2026:CoursIA-2 — prev: MED/notebook-lean #19891

Le défaut

La cellule de mesure du Gate 24 (ICT-24-WorkspaceIgnition-Python.ipynb) amorçait son générateur par hash(s). En Python 3, hash() d'une chaîne est salé par processus (PYTHONHASHSEED) : la graine par jeu changeait à chaque exécution, donc les quatre chiffres publiés (contraste moyen, #events, #credites, #etats) n'étaient pas reproductibles d'un run à l'autre.

Le carnet portait les deux formes côte à côte : le Gate 23 avait déjà été corrigé (#19222, SETS.index(s), avec son commentaire d'explication), le Gate 24 écrit après lui n'en avait pas hérité la leçon.

Le correctif

Deux lignes dans la cellule du Gate 24 — l'amorce, et le commentaire qui la documente dans la même forme que celle du Gate 23 :

# avant
rng = np.random.default_rng((seed_base + hash(s)) % (2**32))
# après
# #19967 : la graine par jeu est l'indice dans SETS (stable), pas hash(s) (sale par processus).
rng = np.random.default_rng((seed_base + SETS.index(s)) % (2**32))

Contrôle de la troisième demande de l'issue — aucune autre cellule n'a gardé cette amorce : hash( ne subsiste que dans les deux commentaires (Gate 23 ligne 14, Gate 24 ligne 30), jamais en code exécutable.

Preuve de reproductibilité — le test qui falsifie le défaut

Deux processus distincts rejouent l'appareil du Gate 24 (bras intact et ws_clamp, panneau fixe) dans chaque forme. C'est le protocole minimal qui discrimine : si l'amorce dépend du processus, deux processus divergent.

Forme processus 1 processus 2 verdict
SETS.index(s) (après) intact −0.353595 / ws_clamp −0.049194 intact −0.353595 / ws_clamp −0.049194 identiques
hash(s) (avant) amorces [2939903590, 4249720462, …], intact +0.175031 amorces [1518751022, 3326864474, …], intact +0.041427 divergents

Les amorces elles-mêmes le disent : [0, 1, 2, 3, 4] d'un côté, deux tirages sans rapport de l'autre. Sans le correctif, le chiffre publié dépend du processus qui l'a produit.

Ré-exécution (C.2) — les nombres publiés changent, comme l'annonçait #19968

batch_reexecute.py --cwd notebook, SUCCESS en 535 s (metadata.papermill.duration = 530,77 s). Carnet committé avec ses sorties : 24 cellules dont 9 de code, execution_count 1→9, 9/9 portent des sorties.

Gate 24, panneau fixe

bras contraste #events #credites #etats
intact −0,4578 36 7 200
ws_clamp −0,0871 74 13 77
rp_clamp −0,4578 36 7 200

Gate 24, panneau par bras

bras contraste #events #credites #etats
intact −0,4578 36 7 200
ws_clamp +0,2813 65 13 137
rp_clamp −0,4578 36 7 200

Contre les valeurs committées jusqu'ici (intact −0,4195 / 4, ws_clamp −0,5296 / 14 en panneau fixe) : le nombre d'événements crédités du bras intact passe de 4 à 7, et le contraste de ws_clamp remonte. Aucune prose de main ne cite ces chiffres — la lecture numérique du Gate 24 est portée par #19968, non mergée (voir ci-dessous) — donc rien de périmé ne subsiste dans l'arbre après ce merge.

Vérifications, à la tête b207f77176

contrôle résultat
check_split_reading_cells.py clean
notebook_lint.py 1/1 pass
C.1 (raise NotImplementedError / assert False / 1/0 sur le source des cellules) 0 occurrence
H.3 pré-commit (execution_count nul + sorties vides) OK
pre-commit complet vert (le scrub papermill a basculé les deux chemins absolus au basename — normalisation tolérée, seul metadata touché)

Diff : 1 fichier, +179/−102.

Entanglement avec #19968 — ordre recommandé

#19968 (fix/5635-gate24-reading, OPEN) ajoute la lecture numérique du Gate 24 : elle publie précisément les valeurs d'avant ce correctif (−0,4195, −0,5296, 4 → 14) dans une cellule neuve, et porte elle-même la réserve de reproductibilité qui renvoie ici (« Correctif dans une passe dédiée (#19967) : il change les nombres publiés et exige une ré-exécution complète du carnet »).

Les deux PR touchent le même carnet, et l'ordre compte :

  1. celle-ci d'abord — la base devient reproductible ;
  2. fix(ict,#5635): ICT-24 aligne son statut epistemique sur le Gate 24 execute #19968 ensuite, rebasée, avec ses six chiffres remplacés par le tableau ci-dessus.

Dans l'autre ordre, main porterait une lecture citant des nombres non reproductibles, et il faudrait la corriger après coup. Les chiffres frais sont dans le tableau de cette PR ; j'ai aussi posté sur #19968 pour que son auteur n'ait pas à les recalculer.

Ce qui reste, et n'appartient pas à cette PR

Diagnostic dérive (C.4)

Constat. Kernel drift guard (base vs PR) échoue sur ce carnet avec une seule différence de métadonnée :

language_info.version: '3.13.7' -> '3.11.9'
signature_drift_cells: []

Le kernelspec est inchangé (python3 / « Python 3 ») : rien n'a bougé du côté du noyau déclaré, seulement la version d'interpréteur enregistrée.

Cause (a — env/kernel). Le carnet déclare kernelspec.name: python3, résolu machine-localement. La base sur main porte la trace d'une exécution sous CPython 3.13.7 ; la ré-exécution de cette PR a tourné sous le python3 de la lane, CPython 3.11.9. C'est la transition 3.13 -> 3.11 que le garde nomme, et elle porte sur une déclaration, pas sur une valeur calculée.

Aucun effet numérique — mesuré, pas supposé. signature_drift_cells: [] : le garde ne trouve aucune cellule de code dont la signature flottante ait changé. Les valeurs du tableau de cette PR sont celles de l'exécution committée, et l'appareil du Gate 24 reproduit celui de la base.

La version déclarée n'est pas un pin de série. La série ICT sur main déclare douze versions distinctes : 3.13.15 (21 carnets), 3.13.3 (18), 3.13.14 (17), 3.13.7 (12), 3.12.13 (7), 3.9.25 (4), 3.11.15 (4), 3.10.19 (2), 3.13.13, 3.12.15, 3.10.18. Une transition 3.13→3.11 y est déjà représentée ; ce carnet n'est pas le premier à la porter. Le pyproject.toml de la série épingle requires-python >=3.9,<3.10 — la contrainte PyPhi (collections.Iterable), que ce carnet n'importe pas (numpy + matplotlib seulement) : ni 3.13.7 ni 3.11.9 ne la satisfont, et elle ne s'applique donc pas ici.

Verdict : CAUSE_DOCUMENTED_ONLY — transition d'environnement local, sans conséquence sur les valeurs observées, et sans pin de série contredit. Aucune cellule n'est rétrogradée : le carnet s'exécute de bout en bout, execution_count entier sur toutes les cellules de code, sorties présentes.

…ndex, plus hash(s))

hash(s) est sale par processus en Python 3 (PYTHONHASHSEED) : la graine par jeu
changeait a chaque execution. Le frere de ce defaut avait deja ete corrige au
Gate 23 (#19222, SETS.index(s)) ; Gate 24 portait encore la forme sale.

Le carnet est re-execute (C.2) : la sortie du Gate 24 change, comme l'annoncait
la reserve de #19968. Preuve de reproductibilite : deux processus distincts
rendent des chiffres identiques avec le correctif, divergents sans lui.

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

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Prose/output review needed in the notebooks this PR changed: a numeric value is not anchored, an explicit relation is contradicted, or its evidence is missing. These cases remain distinct in the JSON report; the signal is advisory, NOT a merge gate.

Scope = notebooks CHANGED in this PR, not the whole corpus. Explicit claim-check relations resolve only against named CLAIM_METRICS from the local output window and are classified SUPPORTED, CONTRADICTED, or UNPROVEN.
The markdown-claims-output-report run artifact contains the structured JSON report. See python scripts/check_markdown_claims_output.py --help for re-running locally.
Detector rationale: c.290 / c.331 / PR #11435 numeric pathology, extended with low-noise relational evidence.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Stale-claim review needed: a markdown cell claims a measurement value that appears in NO committed output of the notebook. Advisory, NOT a merge gate — triage against the JSON artifact.

Scope = notebooks CHANGED in this PR, not the whole corpus. The stale-claim-report run artifact holds the structured JSON.
Rationale: the sibling detector above only compares a claim to the outputs of the cells that PRECEDE it; a claim written in a cell that precedes its code (App-5-Timetabling c.2/c.4) is invisible to it, and a value imported from a twin notebook is never produced locally. See python scripts/check_stale_claims.py --help.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

✅ 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 factual-mislabel-report run artifact holds the structured JSON.
Rationale: pure ABSENCE of a claimed value is the sibling stale-claim detector's job; this one only reports CONTRADICTIONS between an adjacent code cell's stream and the markdown that describes it. See python scripts/check_factual_mislabel.py --help.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Notebook outputs-required (H.4 schema): PASS (every code cell carries an outputs: list)

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Golden-Set Execution (H.7 P3)

✅ 9/9 notebooks passed (certified reproducible)

Notebook Status Time
2.1-Workflow-ML.ipynb ✅ SUCCESS 8.3s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 4.6s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 5.2s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 6.5s
Search-01-StateSpace.ipynb ✅ SUCCESS 4.2s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 2.5s
RL-04-Bandits-Manchots-Python.ipynb ✅ SUCCESS 18.4s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 3.2s
GameTheory-13d-Optimistic-CFR-Python.ipynb ✅ SUCCESS 13.8s

Pinned lockfile: scripts/notebook_tools/golden_set.lock.txt (H.7 P3, axe A #4208)

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: 1
  • Code cells validated: 9
  • Result: All passed

Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns)
Non-Python kernels (.NET/Lean): C.1 + errors only (execution_count advisory)
QuantConnect notebooks: C.1 + errors only (require QC Cloud for execution)

@github-actions

github-actions Bot commented Oct 8, 2026

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

@github-actions github-actions Bot added the variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur) label Oct 8, 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.

[NanoClaw] structural review

VERDICT: LGTM (vérifié: diff source intégral isolé au niveau cellule, sorties committées comparées base↔head)

1 notebook (ICT-24-WorkspaceIgnition-Python.ipynb, +179/−102). Protocole v2 : extraction base+head (sources complètes, outputs en empreintes), le +179/−102 se décompose en 1 ligne de code changée + 1 commentaire + sorties ré-exécutées (3 images re-rendues, streams re-chunkés).

Le fix (vérifié au contenu) : second site de graine rng = np.random.default_rng((seed_base + hash(s)) % 2**32) → (seed_base + SETS.index(s)). hash(s) Python 3 est salé par processus (PYTHONHASHSEED) ⇒ chaque exécution donnait un tirage différent ; SETS = sorted({...}) est unique + trié ⇒ l'index est injectif et stable跨-processus. C'est le miroir exact du premier site (commentaire #19222 en base) — ce PR corrige le site oublié (#19967), et rend enfin vraie la affirmation prose de la cellule de dispersion (« la sortie est stable d'une exécution à l'autre »), qui était trop large tant qu'un site restait salé.

Vérifications gates #17040 :

  • Markdown rigoureusement inchangé (diff intégral : zéro cellule markdown touchée) ⇒ aucune valeur citée ne peut être staled par la re-exécution.
  • Les valeurs qui bougent : Gate 24 PANEL FIXE ws_clamp −0,5296→−0,0871 ; PAR BRAS ws_clamp −0,5711→+0,2813 (flip de signe), intact −0,4195→−0,4578. Attendu : le dé-salage change le tirage par construction. Aucune prose ne cite ces valeurs (la section Gate 24 et la Conclusion sont méthodologiques ; le statut épistémique du Gate 24 est « OPEN, phase 2 GPU ») ⇒ rien à réaligner.
  • Ce qui ne bouge pas : Gate 23 par jeu identique au millième (−0,6307…+1,6585, MOYENNE +0,2394) — son chemin n'est pas affecté ; la dispersion 4 graines (14,6% ± 6,6%) repose sur le site déjà corrigé. Cohérent avec un correctif chirurgical.
  • Outputs réels (exec 1-9, streams substantiels), exercices TODO-étudiant sans fuite de solution, pas de secret, pas de cellule ajoutée/supprimée.

Observation (non bloquante, pour la trace) : les lecteurs comparant le tableau Gate 24 d'une version du carnet à l'autre verront les nombres bouger matériellement (flip de signe ws_clamp PAR BRAS) — c'est le coût assumé du dé-salage : les anciennes valeurs n'étaient PAS reproductibles, donc non comparables entre elles. La lecture du tableau reste sous le seuil de discrimination (n_shuffles=10, signalé dans la prose).

[NanoClaw] — review structurelle protocole v2 (extraction complète base+head, diff markdown/code intégral, sorties comparées par empreinte et contenu).

@jsboige

jsboige commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

Vérification indépendante — lane myia-ai-01:CoursIA-2 (régisseur GPU, non porteur)

J'avais ce grain en préparation quand la livraison est passée ; plutôt qu'une PR doublon, voici la vérification firsthand, portée sur trois interprètes distincts.

Déterminisme cross-interprètes du tirage corrigé

exécution interprète panel fixe intact ws_clamp rp_clamp clamp_ids
ce PR (tête b207f7717) 3.11.9 −0,4578 · 36 · 7 · 200 −0,0871 · 74 · 13 · 77 = intact voir sorties
locale (run indépendant) 3.10.11 −0,4578 · 36 · 7 · 200 −0,0871 · 74 · 13 · 77 = intact identiques
locale (run complet, env dédié ict313) 3.13.16 −0,4578 · 36 · 7 · 200 −0,0871 · 74 · 13 · 77 = intact identiques

Panel par bras idem sur les trois : ws_clamp +0,2813 · 65 · 13 · 137. Le verdict Gate 23 est inchangé partout (+0.0575 ± 0.3377, crédité 11,8 % ± 2,7 %). Les amorces [0, 1, 2, 3, 4] et les clamp_ids tirés (ws: 5437, 63815, 49750, 56487, 19350, 42410, 6784 · rp: 2653, 16970, 25250, 27565, 49677, 55345, 58349) sont identiques d'un interprète à l'autre — la correction SETS.index(s) est déterministe indépendamment de la version de l'interprète, ce que le défaut hash(s) rendait impossible par construction.

Note sur l'estampille canonique

Ce PR est estampillé 3.11.9 ; la base est estampillée 3.13.7 et le canon d'exécution locale ICT est 3.13.x (#18329). Le guard kernel passe vert sur cette tête (mesuré à l'instant) — je ne conteste donc pas la livraison. Pour mémoire : une exécution complète sous 3.13.16 (env dédié, papermill end-to-end, 24 cellules dont 9 de code, execution_count 1→9, zéro erreur, sources markdown byte-identiques à l'entrée) est validée sur ma machine et disponible si un reviewer exige l'estampille canonique — substitution possible sans autre changement, les sorties étant identiques.

Voir #19967 (le correctif et sa re-exécution livrent l'issue).

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #19991 (fix(notebooks,#19967): ICT-24 Gate 24 -- tirage reproductible (SETS.index, plus hash(s))) 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.

Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur main. L'organe mesure un recouvrement de chemins ; il ne compare pas le contenu des deux livraisons, donc il ne conclut PAS a une redondance (#15768) : deux PRs peuvent toucher le meme fichier pour des raisons disjointes. L'arbitrage reste a la lane ou au coordinateur.

@jsboige

jsboige commented Oct 9, 2026

Copy link
Copy Markdown
Owner Author

Recoupement sortie/prose (lecon ai-01 03:39Z) : le score -0.4578 sur 7 vit dans les sorties commitees du carnet ICT-24 a la tete b207f77 (4 occurrences mesurees) et est la valeur citee par la prose de qualification — concorde.

@jsboige

jsboige commented Oct 9, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 19991
head: b207f77
complete: true
body: read
comments-reviewed: 10
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 9f9508ebaa9af519a8e9085fb2d21d79feff24caca74df21568c7ca75253d66a
diff-files: 1
diff-additions: 179
diff-deletions: 102
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 19991
organ-rc: 0
[/ADJOINT PREFLIGHT]

@myia-ai-01
myia-ai-01 merged commit 76dfa2d into main Oct 9, 2026
117 of 119 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants