Repository navigation
fix(training,#14362): la jambe de sanite DM etait silencieusement recentree - #14392
Conversation
…g the verdict leg `run_btc_debiased_recentered` computes two DM legs: a verdict leg on centered errors vs de-biased HAR, and a sanity leg meant to reproduce the #11011 keeper on raw losses vs raw HAR. Both went through `_dm_centered_mse`. The two HAR series differ by exactly a constant (`har_errors_debiased = har_errors - har_bias_oos`), and centering by each series' own mean annihilates precisely that constant: `(e - c) - mean(e - c) = e - mean(e)`. The legs returned the same number -- bit-identical on 12 of 12 rows of the published artefact. A control that cannot go red is not a control. The artefact contradicted its own stated purpose: the sanity leg's p_medians (1.545e-09 / 9.660e-05 / 1.021e-01) reproduced `dm_centered_p_median`, not the keeper (0.00e+00 / 2.25e-10 / 2.39e-09) -- and at h=10 it reported INCONCLUSIVE where the keeper it was meant to retrieve publishes BEATS. Delivered: - `_dm_uncentered_mse`: DM with loss_fn="mse" on untouched errors, same return shape and sentinels as its twin. The sanity leg now calls it on raw series. - Rename `dm_raw_*` -> `dm_uncentered_vs_har_raw_*` (names both properties; zero consumers repo-wide, verified by grep). `dm_centered_*` left untouched -- that one IS consumed by committed notebook cells. - 7 tests, including the sealed control and its falsification (`test_old_composition_is_degenerate` proves the old path collapses, so the main assertion is not incidental). Verified by mutation: reintroducing the regression fires 3 of 3 guards. Full suite: 1089 passed, 1 skipped. - Artefact regenerated at identical config. `dm_centered_stat` returns bit-identical on 12/12 rows (max delta 0.000e+00); the corrected leg now matches the keeper in magnitude and verdict, recovering BEATS at h=10 (p = 3.08e-09 vs keeper 2.39e-09). Legs now coincide on 0/12 rows. - Notebook re-executed end-to-end (C.2: cell 24 prints `elapsed_s`), which also closes a pre-existing machine-path leak in its papermill metadata. - REGISTRY.md correction note; the entry described this leg as reproducing the keeper, and it did not. The verdict is unaffected: `aggregate_verdicts_recentered` reads only `dm_centered_*`. M4 stays confirmed h=1/h=5 + INCONCLUSIVE h=10; M15 stays refuted-de-biased 3/3. The defect cost the ability to check that, not the result itself. Closes #14362 See #14390 Co-Authored-By: Claude-Code <noreply@anthropic.com>
Notebook PR Validation: PASS
Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns) |
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
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 |
Golden-Set Execution (H.7 P3)✅ 8/8 notebooks passed (certified reproducible)
Pinned lockfile: |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[NanoClaw] structural review (budget diff — file list + 2 fichiers porteurs lus au head, vérifs mécaniques ciblées) — VERIFIED au head 5d8aa04.
Le fix, vérifié ligne à ligne. _dm_uncentered_mse passe bien les erreurs intactes à dm_verdict_fn (aucun centrage), avec les mêmes sentinelles (SHAPE_MISMATCH, INSUFFICIENT_DATA < 10) et la même forme de retour que sa jumelle — la docstring énonce la cause racine (#14362) noir sur blanc. Le site d'appel est correct : jambe sanité = _dm_uncentered_mse(dl_errors, har_errors) raw-vs-raw, avec le commentaire expliquant pourquoi elle ne doit PAS passer par le helper centré (constante annihilée par le recentrage). Renommage complet vérifié dans l'artefact régénéré : clés dm_uncentered_vs_har_raw_* présentes, 0 clé dm_raw_* résiduelle ; dm_centered_* inchangé (l'agrégation lignes 251-297 et le notebook ne lisent que lui — rien ne casse).
Les gardes tirent sur la faute qu'elles visent. Le contrôle scellé (test_legs_are_not_the_same_statistic, seuil >1e-6) est adossé à sa falsification : test_old_composition_is_degenerate rejoue l'ancienne composition et montre la collision bit-identique (abs=1e-12) — sans lui, le scellé pourrait passer pour une raison étrangère au centrage. La propriété est testée dans les deux sens (centrée invariante par translation / non-centrée ne l'est pas), le test substantif test_uncentered_leg_sees_a_pure_bias_gap construit un gap de pur biais (har = dl + 1.5, dispersion identique) : non-centrée le voit (BEATS, p<1e-6), centrée aveugle (dm_stat≈0, INCONCLUSIVE) — exactement l'histoire #11011. Guard-the-guard présent (test_biases_actually_differ_in_the_fixture, >0.1). Sentinelles paritaires testées.
L'artefact régénéré, re-vérifié à la main : 12 rows, coïncidence des deux jambes 0/12 (le bug la rendait 12/12), flip h=10 confirmé au seed 0 (non-centrée p=3,2e-9 BEATS / centrée p=0,103 INCONCLUSIVE), verdicts BEATS 4/4 aux 3 horizons. Médianes de la table REGISTRY recalculées depuis les 12 rows committés = exactes (h1 0.000e+00, h5 1.435e-10, h10 3.083e-09) — la provenance est prouvée, pas déclarée. Cross-check interne bonus : les valeurs de l'« ancienne jambe buggée » du body (1.545e-09 / 9,66e-05 / 1,021e-01) coïncident avec les dm_centered_p_median de l'artefact neuf — cohérent par construction, le bug identifiait les deux jambes.
Notebook + registre. 14/14 cellules code execution_count séquentiels, 0 sortie d'erreur, papermill.exception: null, fuite de chemin refermée (input/output_path relatifs, plus de C:\dev\...). REGISTRY.md porte la note de correction datée #14362, honnête sur la nature de l'accord (rang de grandeur et verdict, pas bit-à-bit — reproduction indépendante, pas rejeu). CI au head : gardes notebook-health 10/10 success. 0 secret (grep ghp_/hf_/AKIA/sk- sur les fichiers porteurs).
2 notes mineures (non bloquantes) :
- La section
aggregatedde l'artefact ne porte quedm_centered_p_median— un champdm_uncentered_vs_har_raw_p_mediany donnerait à la jambe de sanité la même provenance committée qu'à la jambe de verdict (aujourd'hui la table REGISTRY se re-dérive à la main des rows — je l'ai fait, ça tombe juste, mais un champ agrégé l'éviterait). test_uncentered_leg_sees_a_pure_bias_gapasserte le libellé exact"BEATS baseline"— couplage au vocabulaire dedm_test; un renommage de verdict dans la lib casserait le test pour une raison étrangère au centrage (le reste de la suite utilise les mêmes libellés, donc cohérent — juste à savoir).
Green-lightable : chaque claim du body vérifié mécaniquement, le garde scellé est falsifié dans le bon sens, et la correction du registre assume ce que l'artefact prouve.
…ok 06 (sync-over-async, deux variantes) (#14396) * feat(aspire,#10473): section D1 -- AGENTGUARD005 livre dans le notebook 06 (sync-over-async, deux variantes) EPIC #10473 (The Unexpected AI Stack, axe Roslyn) : AGENTGUARD005 et AGENTGUARD005b sont livres dans AgentGuard.Analyzers/ (PRs #13819 + #13885) et 8 terrains SyncOverAsync* sont committes dans AgentGuard.Verifier/samples/, mais le notebook 06 n'en parlait pas. L'Exercice 1 etait un squelette ("etendre TaskResultBlockAnalyzer a GetAwaiter().GetResult()") qui designait precisement l'analyseur deja livre. Cette PR comble le trou pedagogique. - Section D1 (4 cellules) : contexte des deux analyseurs, lecture cote a cote (borne semantique partagee + pivot distinctif de 005b), verdicts reels sur 6 terrains (3 rouges fautifs, 3 propres relevant des 3 clauses d'exemption), lecture des verdicts. - Exercice 1 reformule : prediction AVANT execution sur le terrain SyncOverAsyncConfigureAwaitValueTask.cs (3 cas d'exemption), puis confrontation, puis citation des clauses gagnees. Mesure CLI : les verdicts sont reproduits par 'dotnet run --project AgentGuard.Verifier --' (sortie verbatim dans le body PR). Grain: MED/notebook-dotnet -- lane myia-po-2024:CoursIA-2 -- prev: MED/training #14392 G-VAR-1 tenu (genre CONTENU, tier MED). Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * chore(ci,#14396): wake PR gate (body INCIDENTAL count) -- reaffirme 1 fichier pousse, 8 terrains SyncOverAsync upstream verifies * fix(aspire,#14396): renuméroter exec_count 1..N + convertir cellule D1 en md Réparation de PR #14396 (c.873 c.877) : le gate 'Exec-sequence ratchet (base vs PR)' échouait avec CLEAN->DUPLICATE sur 06-Aspire-GardeFous-Roslyn.ipynb après l'insertion de la section D1 sans ré-exécution du notebook. La séquence execution_count était [1,2,3,2,5,..,9,1,2,10,..,18] au lieu de 1..N. Constat firsthand : - 4 nouvelles cellules D1 insérées entre cell 22 (ec=9) et cell 30 (ec=10) avec execution_count 1,2,10,11 au lieu de 10,11,12,13,14,15,16,17,18 - cellule 25 (l'illustration côte-à-côte des analyseurs) avait une chaîne C# Console.WriteLine avec un backtick ` dans une string literal non échappée — erreur CS1056, non-détectée par c.873 - le notebook n'avait pas été ré-exécuté de bout en bout après l'enrichissement (C.2 violation latente) Réparations : 1. conversion cellule 25 (Console.WriteLine de strings statiques) en cellule markdown : le contenu était de la prose illustrative, sans computation réelle — le bloc de code échouait à cause du backtick non échappé et n'apportait aucune valeur ajoutée 2. ré-exécution complète .NET Interactive sur kernel .net-csharp (17 cellules code, 0 erreur), séquence execution_count désormais CLEAN = [1..17] Vérifications post-fix : - check_exec_ratchet.py origin/main : regressions: 0, CLEAN->CLEAN - check_papermill_ratchet.py origin/main : BLOCK_REMOVED (autorisé par #11155) - check_source_output_ratchet.py origin/main : 0 stale cells - check_notebook_navlinks.py : 0 broken links - 17/17 cellules code avec execution_count, 17/17 avec outputs, 0 output error Ref: #14396 (PR repair, même branche feature/c873-agentguard005-section) * fix(asipre,#14396): strip probeAddresses banner from 06-Aspire-GardeFous-Roslyn cell 6 output c.880 REPAIR: c.878 .NET re-exec re-injected the .NET Interactive probeAddresses banner via NetworkInterface enumeration, contaminating display_data cell output. Stop & Repair surgical strip via scripts/notebook_tools/strip_probe_banner.py --apply -- rewrites text/html to '' while preserving output_type=display_data structure (no source touched, no execution_count changed). CI banner guard now clean. Verified: python strip_probe_banner.py --scan = 0 banner lines. Grain: MED/notebook-dotnet (repair) -- lane myia-po-2024:CoursIA-2 -- prev: MED/tooling #14440 Co-Authored-By: Claude-Code <noreply@anthropic.com> * fix(asipre,#14396): Exercice 1 cellule 10 -- Verifier exige args.Length >= 2 (Hermes c.883) (#14460) Constat Hermes 2026-09-03T00:25:18Z : la cellule 10 (Exercice 1) invoquait le Verifier avec 1 seul argument (SyncOverAsyncConfigureAwaitValueTask.cs), mais Program.cs:13 retourne exit 2 + banner 'usage:' si args.Length < 2. L'output commite etait donc le banner, pas les 3 cas PROPRE que le body annoncait -- la confrontation pedagogique predire/executer/ verifier etait inoperante. Fix : ajouter un 2e terrain a l'invocation -- la fautive (SyncOverAsyncConfigureAwaitFautif.cs, 2 diagnostics AGENTGUARD005b sur ConfigureAwait(false)/(true).GetAwaiter() .GetResult()) + la valueTask (3 diagnostics PROPRE). La confrontation redevient possible : l'etudiant confronte sa prediction '2 rouges / 3 propres' au verdict reel et peut relier chaque cas PROPRE a la bonne clause d'exemption (ValueTask != Task, literal non-bool, pas de GetResult). Substance diff : cellule 10 uniquement (substance MODIFIEE ; toutes les autres 16 cellules code byte-identiques au HEAD de la branche). Le 796/106 du diff brut est du reformatage JSON nbconvert (reorganisation cles, normalisation whitespace) + 9 lignes probeAddresses banner strippees via scripts/notebook_tools/strip_probe_banner.py --apply. Verifications : - check_exec_ratchet.py origin/main : CLEAN->CLEAN (seq 1..17) - check_papermill_ratchet.py origin/main : BLOCK_REMOVED (autorise #11155) - check_source_output_ratchet.py origin/main : 0 stale cells - check_notebook_navlinks.py : OK 0 lien casse - C.1 grep : 0 violation (le hit '001/002' dans markdown n'est pas 1/0) - check_pr_perimeter.py 14396 : VERDICT OK - Cellule 10 re-executee kernel .net-csharp : ec=4, output = 2 diagnostics AGENTGUARD005b + VERDICT PROPRE (au lieu de banner usage) Genre : MED/notebook-dotnet (REPAIR herite du genre substance, G-VAR-1 TENU). Lane myia-po-2024:CoursIA-2. --------- Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Grain: MED/training — lane myia-po-2024:CoursIA-2 — prev: DEEP/qc #14369
La jambe
dm_rawderun_btc_debiased_recenteredétait censée porter la sanité : un DM sur pertes brutes, contre HAR brute, reproduisant le keeper #11011. Elle passait par_dm_centered_mse, comme la jambe de verdict. Ce n'est pas un détail de nommage : les deux HAR ne diffèrent que d'une constante, et le recentrage par la moyenne propre annule exactement une constante — les deux jambes rendaient le même nombre.La falsification, sans rien construire
L'artefact commité contredit lui-même ce que la jambe prétendait mesurer. Ses p-médianes « raw », comparées à ce qu'elle devait reproduire :
dm_rawp_median (artefact)dm_centered_p_medianpublié (#12734)La jambe « brute » reproduisait la jambe recentrée à la précision d'impression près — pas le keeper. À h=10 elle rendait
INCONCLUSIVElà où le keeper qu'elle devait retrouver publieBEATSà p = 2,39e−09 : sept ordres de grandeur et un verdict retourné. Un contrôle qui suit la mauvaise cible n'en est pas un.Sur les 12 combos,
|dm_raw_stat − dm_centered_stat|vaut 0 exactement sur 8 lignes, et 1,78e−15 / 8,88e−16 / 2,22e−16 sur les 4 autres.La cause, tracée
d'où
har_errors_debiased = har_errors − c, et_dm_centered_mse— dont la docstring énonce « Centering annihilates the bias component » — calcule(e − c) − mean(e − c) = e − mean(e). Deux arguments différents, même fonction, même sortie. La lecture des seuls sites d'appel montre un contraste ; c'est la composition avec le helper qui l'annule.Ce qui est livré
_dm_uncentered_mse— DMloss_fn="mse"sur erreurs intactes, mêmes sentinelles (SHAPE_MISMATCH,INSUFFICIENT_DATA) et même forme de retour que sa jumelle. La jambe de sanité l'appelle surdl_errorsvshar_errorsbruts.dm_raw_*→dm_uncentered_vs_har_raw_*, qui nomme les deux choses (non centré, contre HAR brute). Le nom précédent était réellement ambigu — « raw » se lisait « perte brute » alors qu'il signifiait « contre HAR brut ». Vérifié augrep: zéro consommateur hors du script.dm_centered_*reste inchangé : celui-là est consommé (m4_dlinear_vol_sc_validation.ipynb, cellules 24/26/30), le renommer casserait des sorties commitées sans qu'aucune cellule ne lève.test_old_composition_is_degeneraterejoue l'ancienne composition et prouve qu'elle s'effondre — sans quoi le test principal pourrait passer pour une raison étrangère au centrage. Plus les deux sens de la propriété : la jambe centrée est invariante par translation constante, la non centrée ne l'est pas.--horizons 1 5 10 --seeds 0 7 42 99 --epochs 50), le notebook re-exécuté (C.2), et la note de correction auREGISTRY.md— l'entrée training(#1454): re-valider les keepers BTC hors biais — M4 survit numeriquement, M15 invérifiable post-hoc #12734 décrivait cette jambe comme « RAW = sanité reproduisant le keeper » ; elle ne le faisait pas, et le registre doit le dire.La vérification post-régénération — les deux contrôles
Artefact régénéré à configuration identique (1776,4 s, 12 combos). Deux contrôles, tous deux falsifiables.
(A) Rien d'autre n'a bougé.
dm_centered_statrevient bit-identique sur 12 lignes sur 12, Δ max = 0,000e+00 — M4 est déterministe et seedé, donc c'est la forme la plus forte que ce contrôle puisse prendre. La jambe de verdict n'a pas frémi.(B) La jambe corrigée retrouve le keeper qu'elle existe pour reproduire :
Et à dire honnêtement : sur h=5 et h=10 l'accord est de rang de grandeur et de verdict, pas bit-à-bit (facteur < 2). Le keeper vient d'un entraînement DLinear distinct — les erreurs du modèle ne sont pas les mêmes séries. C'est l'accord attendu d'une reproduction indépendante, pas d'un rejeu, et je ne le présente pas pour plus que ça. Ce qui compte est le renversement à h=10 :
INCONCLUSIVEà p = 0,102 →BEATSà p = 3,08e−09, là où le keeper publie BEATS à 2,39e−09.(C) Les deux jambes coïncident désormais sur 0/12 lignes (contre 12/12).
Le notebook
m4_dlinear_vol_sc_validation.ipynbre-exécuté end-to-end via papermill (C.2) : sa cellule d'index 24 imprimeelapsed_s, que la régénération fait passer de 1787 s à 1776 s. 14/14 cellules code avecexecution_count, 0 sortie d'erreur,papermill.exception: null. Aucun chiffre de résultat ne bouge — corollaire attendu du contrôle (A), puisque le notebook ne lit quedm_centered_*.Effet de bord bienvenu : le
metadata.papermill.input_path/output_pathcommité pointaitC:\dev\CoursIA-c1331p441-12734\...(fuite de chemin machine préexistante surmain, quescrub_papermill_paths.py --scansignalait). La ré-exécution en chemins relatifs la referme —--scanet--scan --outputsrendent 0.Comment le défaut a survécu — et ce que je diffère
Le bloc
aggregatedde l'artefact ne contient quedm_centered_p_median: la jambe de sanité n'était agrégée nulle part. Elle existait en champ par ligne, que rien ne résumait et que rien ne confrontait au keeper qu'elle prétendait reproduire. Une jambe qu'on ne lit jamais ne peut pas rougir, même quand elle est correcte — le centrage silencieux n'a fait que rendre l'aveuglement total.L'agréger (
dm_uncentered_vs_har_raw_p_median, à côté de sa jumelle) rendrait la comparaison au keeper lisible là où on la cherche. Je le diffère délibérément : la régénération de 30 min était déjà lancée quand je l'ai constaté, et l'ajouter imposerait un second run complet pour un champ additif. Suivi : #14390, ouverte avant cette PR. Les valeurs par ligne étant présentes, le contrôle est falsifiable dès cette PR — la médiane se calcule, elle n'est simplement pas pré-écrite.Ce que cela n'invalide pas
Rien du verdict.
aggregate_verdicts_recenteredne lit quedm_centered_pvalueetdm_centered_verdict, corrects : M4 resteconfirmedh=1/h=5,INCONCLUSIVEh=10 ; M15 resterefuted-de-biased3/3. Le défaut portait sur un champ de diagnostic. Ce qui était perdu, c'est la capacité de le contrôler — et c'est ce que cette PR rend.Closes #14362