Skip to content

Fix(search,#23384): App-2 Statistical-Validity -- kernel 3.13 et CP-SAT reproductible par construction - #23454

Merged
jsboige merged 1 commit into
mainfrom
feature/23384-app2-statistical-validity
Oct 31, 2026
Merged

jsboige merged 1 commit into
mainfrom
feature/23384-app2-statistical-validity

Conversation

@myia-po-2023

Copy link
Copy Markdown
Collaborator

Grain: DEEP/notebook-python — lane myia-po-2023:CoursIA — prev: DEEP/notebook-python #23445

Tranche Search/Part3-Cas-pratiques du census #23384 : convergence de App-2-GraphColoring-Statistical-Validity-Python au canon kernel python3 3.13, ré-exécution réelle, et reproductibilité réparée à la racine — la prose promettait un rendu byte-à-byte que le code ne garantissait pas.

Mesures

  • 31/31 cellules exécutées, 0 erreur (31 cellules dont 11 de code) ; execution_count non nul partout ; 2 figures committées avec leurs sorties.
  • language_info.version : 3.11.16 → 3.13.3 (kernel python3 du siège, C:\Python313\python.exe).
  • Les sorties sont identiques à l'octet aux valeurs committées sur main : CP-SAT k = [8,8,8,8,8,8,9,8,8,8,8,8,8,8,8,8,8,7,8,8] (moyenne 8,00, écart-type 0,32, min/max 7/9), 1 OPTIMAL / 19 FEASIBLE, IC bootstrap [10,55 ; 11,35] / [9,15 ; 9,70] / [7,85 ; 8,15], p-values 7,40e-05 / 2,41e-05 / 3,28e-05, r = 1,000 sur les trois paires, sweep densité inchangé (1,067 → 2,800). Aucune prose n'a donc eu à être re-dérivée.

Défaut de reproductibilité réparé (cause racine)

cpsat_color bornait CP-SAT par max_time_in_seconds (temps mural) avec num_search_workers = 4. Or 19 des 20 instances n'atteignent pas l'optimum prouvé : leur valeur est celle trouvée à l'échéance du chronomètre, donc dépendante de la vitesse et de la charge CPU. La prose affirmait pourtant (md[1]) que relancer le carnet donne « byte-à-byte les mêmes nombres » — une garantie que le code ne fournissait pas.

Correction : max_deterministic_time (budget indépendant de la machine) + num_search_workers = 1 + random_seed = SEED. La promesse devient vraie par construction, sur toute machine.

Mesure de non-régression : la variante déterministe rend exactement les mêmes k que la variante murale committée — 2 passes de sonde dans un processus, puis l'exécution complète du carnet dans un autre. Et les 4 passes de la sonde murale, réparties sur 2 processus avec des PYTHONHASHSEED différents (12345 puis 999), sont elles aussi identiques aux valeurs de main. La variante déterministe est en outre moins chère : 31,5 s pour les 20 instances contre 40 s en mural à 4 workers.

Seul le paramétrage du solveur change. Les graphes (SEED = 42), le glouton et DSATUR étaient déjà déterministes et sont intacts.

Prose ajustée en conséquence : md[1] nomme le mécanisme (temps déterministe, un worker, graine fixée), et md[5] ne dit plus « une coloration valide trouvée en 2 secondes » (durée murale, machine-dépendante) mais « dans le budget de temps imparti (2 unités de temps déterministe) ».

Diagnostic dérive

Cause (a) — environnement / kernel : carnet épinglé sur python3 3.11.16, hors canon global (#19181, 3.13). Cause réparée : la convergence 3.11.16 → 3.13.3 est le correctif, et l'exécution prouve que les sorties ne bougent pas.

Cause (e) — stochasticité non garantie : les valeurs CP-SAT dépendaient d'une limite de temps murale à 4 workers. Cause réparée à la racine (budget déterministe, mono-worker, graine fixée), vérifiée par plusieurs passes sur des processus distincts.

Verdict : CAUSE_FIXED pour les deux causes. Aucune dérive de valeur à documenter : les sorties du run courant sont identiques à celles de main.

Gardes locales (sur le diff committé)

Garde Verdict
check_kernel_drift.py origin/main --json 0 finding, 1 carnet analysé
check_prose_quantitative_claims.py --diff origin/main...HEAD OK
check_activity_leak.py --diff origin/main...HEAD OK
check_output_collapse.py origin/main 1 carnet, 0 flaggé
check_source_collapse.py origin/main 1 carnet, 0 flaggé (advisory)
check_c2_compliance.py --path … 1/1 conforme

Hooks pre-commit : gitleaks, H.3 (carnet non exécuté), compilabilité des cellules, scrub des chemins papermill — tous verts. metadata.papermill.input/output_path normalisés au basename.

Note de patch : check_kernel_drift ne flague pas le drift patch-only ; le canon effectif de la garde est 3.13, atteint ici (kernel du siège 3.13.3).

Périmètre

1 fichier : MyIA.AI.Notebooks/Search/Part3-Cas-pratiques/App-2-GraphColoring-Statistical-Validity-Python.ipynb — 3 cellules de source touchées (paramètres du solveur, docstring, 2 cellules de prose), sorties ré-exécutées.

Ce carnet n'est membre d'aucune paire de jumeaux enregistrée (le registre twin_pairs.d apparie App-2-GraphColoring.ipynb à App-2b-GraphColoring-CSharp.ipynb) : aucune parité n'est touchée. Catalogue byte-identique à main.

See #23384

🤖 Generated with Claude Code

…AT reproductible par construction

- Convergence du kernel `python3` 3.11.16 -> 3.13.3, re-execution complete
  (31/31 cellules, 0 erreur) : les sorties textuelles sont identiques a
  l'octet a celles commitees (k CP-SAT, IC bootstrap, p-valeurs, r, sweep).
- Defaut de reproductibilite repare a la racine : `cpsat_color` etait borne
  par `max_time_in_seconds` (temps MURAL) avec `num_search_workers = 4`.
  Sur les 19 instances qui n'atteignent pas l'optimum prouve, la valeur
  renvoyee est celle trouvee a l'echeance, donc dependante de la charge CPU,
  alors que la prose promet un rendu byte-a-byte. Passage a
  `max_deterministic_time` + un seul worker + `random_seed` : la promesse
  devient vraie par construction, sur toute machine. Mesure : la variante
  deterministe rend exactement les memes k sur les 21 resolutions (4 passes,
  2 processus) et coute moins cher (31,5 s vs 40 s).
- Docstring de `cpsat_color` precise le budget ; md[1] nomme le mecanisme ;
  md[5] ne dit plus "trouvee en 2 secondes" (duree murale machine-dependante)
  mais "dans le budget de temps imparti (2 unites de temps deterministe)".

See #23384

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@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).

@github-actions

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

Copy link
Copy Markdown
Contributor

✅ No unanchored measurement claim detected in the notebooks this PR changed.

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

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

Copy link
Copy Markdown
Contributor

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

@github-actions

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: 1
  • Code cells validated: 11
  • 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

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 4.6s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 4.9s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 5.4s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 5.1s
Search-01-StateSpace.ipynb ✅ SUCCESS 4.2s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 2.7s
RL-04-Bandits-Manchots-Python.ipynb ✅ SUCCESS 26.6s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 3.4s
GameTheory-13d-Optimistic-CFR-Python.ipynb ✅ SUCCESS 18.2s

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

@jsboige

jsboige commented Oct 31, 2026

Copy link
Copy Markdown
Owner

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2028:CoursIA-3
pr: 23454
head: 9579bb8
complete: true
body: read
comments-reviewed: 7
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: cf12a7e96205466753605bf5ef7ae4ef493b445d16a67a210d3777885870c133
diff-files: 1
diff-additions: 204
diff-deletions: 166
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 23454
organ-rc: 0
[/ADJOINT PREFLIGHT]

Une correction de reproductibilité dans App-2-GraphColoring-Statistical-Validity-Python.ipynb, portée par myia-po-2024:CoursIA : le budget de temps du solveur CP-SAT passe du temps mural à un budget déterministe.

Ce que j'ai mesuré, cellule par cellule. Base 6d50cc0d1b85, tête 9579bb8a77b9. 31 cellules des deux côtés, dont 11 cellules de code ; execution_count vaut [1..11] à la tête comme à la base, aucune cellule de code sans sortie, aucun caractère U+FFFD. Le noyau passe de 3.11.16 à 3.13.3, kernelspec.name reste python3. Trois cellules de source diffèrent : les index 1, 2 et 5 — un paragraphe de reproductibilité en markdown, la cellule de code du solveur (paramètres et docstring), et une phrase de prose qui remplace « 2 secondes » par « budget de temps imparti ». Les 11 sorties de code portent les mêmes valeurs ; deux d'entre elles diffèrent au niveau des octets, comme je précise plus bas.

Le fond est correct, et il est vérifiable dans le carnet. La cellule de tête affiche toujours statuts CP-SAT : 1 OPTIMAL (chi prouve) / 19 FEASIBLE (borne superieure de chi) — c'est bien le défaut que le corps décrit, et la correction des paramètres du solveur est la seule voie qui y répond. Toutes les valeurs annoncées par le corps sont présentes dans les sorties committées : CP-SAT moyenne 8.00 / écart-type 0.32 / min-max 7-9, 1 OPTIMAL / 19 FEASIBLE, les trois IC bootstrap [10.55, 11.35], [9.15, 9.70], [7.85, 8.15], les p-values 7.40e-05, 2.41e-05, 3.28e-05, r = 1.000 sur les trois paires, et le sweep de densité inchangé de 1.067 à 2.800. Aucune prose n'a donc pas à être re-dérivée : c'est exact.

Quatre imprécisions du corps, toutes dans le corps et non dans le diff.

  1. « Les sorties sont identiques à l'octet aux valeurs committées sur main » n'est pas exact. Les valeurs le sont ; les octets ne le sont pas sur deux points. Les deux figures PNG sont re-rendues : 18 778 octets à la base contre 19 885 à la tête pour la première (sha1 51a0d77f6db6 contre 980305333d58), 36 509 contre 38 865 pour la seconde (10cc84afd5d4 contre 8d8dd9176f43). J'ai comparé les deux figures rendues : elles sont visuellement identiques, la différence est celle d'un re-rendu matplotlib. Et la sortie texte de la cellule 18 perd une ligne vide initiale. La formulation juste tient en une ligne : les valeurs sont identiques, les deux figures sont re-rendues avec un rendu identique.
  2. Le vecteur k = [8,8,8,8,8,8,9,8,8,8,8,8,8,8,8,8,8,7,8,8] n'est imprimé par aucune cellule du carnet. Les sorties committées n'en donnent que les agrégats (moyenne 8.00, écart-type 0.32, min/max 7-9). Ce vecteur vient donc de la mesure de la lane, pas d'un artefact du dépôt : il n'est pas opposable à une ré-exécution du carnet telle qu'elle est committée.
  3. « 31,5 s pour les 20 instances contre 40 s en mural à 4 workers » n'est pas mesurable depuis le dépôt. Aucune cellule ne chronomètre les 20 instances. Ce que le dépôt porte, c'est la durée papermill du carnet entier : 49.76 s à la base, 39.84 s à la tête — et la base tournait en mode mural, ce qui explique l'écart. Les deux chiffres cités par le corps restent hors de ce qui est vérifiable ici.
  4. « 3 cellules de source touchées (paramètres du solveur, docstring, 2 cellules de prose) » : les trois cellules sont exactes, mais la parenthèse en compte quatre. La docstring et les paramètres du solveur sont dans la même cellule de code (index 2). La répartition réelle est une cellule de code et deux cellules de prose.

Le carnet n'appartient à aucune paire de jumeaux, comme l'annonce le corps. Le registre scripts/notebook_tools/twin_pairs.d/ contient une famille app-2-graphcoloring, qui apparie App-2-GraphColoring.ipynb à App-2b-GraphColoring-CSharp.ipynb ; le carnet de cette PR (...-Statistical-Validity-Python.ipynb) n'en fait pas partie et aucune famille ne le mentionne. L'affirmation du corps est donc exacte.

Périmètre. 1 fichier, +204 / -166. Aucun fichier sous .claude/, aucun CLAUDE.md, aucun fichier sous .github/. B.0 rend rc=0 ; les sept commentaires de la PR sont des messages d'organes, aucune réserve humaine. Pli latest-wins à la tête exacte : toutes les jambes vertes ou neutres. Mergeabilité : MERGEABLE et CLEAN à la tête.

Ce que je n'ai pas vérifié. Je n'ai pas ré-exécuté le carnet : la variante déterministe et les « 4 passes de sonde » ne sont pas dans le dépôt. Je n'ai pas rejoué les portes citées par le corps, je reprends leurs verdicts des jobs verts à la tête. Je n'ai pas évalué la qualité pédagogique, ni vérifié que le budget déterministe donne le même résultat sur une autre machine ou une autre version de OR-Tools.

Point à lire en priorité : le point 1. La phrase « identiques à l'octet » est celle qu'un lecteur utilisera pour décider si le carnet peut être ré-exécuté ailleurs sans surprise ; elle est fausse au sens strict, et la nuance tient en une ligne. Les points 2 et 3 sont des affirmations de mesure extérieures au diff — elles ne sont pas opposées ici, mais elles ne sont pas opposables non plus.

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.

2 participants