Skip to content

feat(iit,#8236): ICT-42c hysteresis de l'inoculation -- clamp alpha(t) triangulaire, traces 1.7B + 2B - #20253

Open
jsboige wants to merge 2 commits into
mainfrom
feature/8236-hysteresis
Open

jsboige wants to merge 2 commits into
mainfrom
feature/8236-hysteresis

Conversation

@jsboige

@jsboige jsboige commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Grain: DEEP/notebook-python — lane myia-po-2027:CoursIA-2 — prev: LIGHT/docs #20241

See #8236 (tranche « hysteresis multi-passes » du claim ai-01 du 2026-10-06 : « 4e échelle d'inoculation (27B ou A3B) et/ou hysteresis multi-passes jamais livrée, une PR par carnet avec traces .npz et QA-vision »)

Summary

Lève la limite 1 assumée du pilote ICT-42 (« pas d'hystérésis (clamp par passe) ») : l'intensité d'inoculation constante α devient un profil dépendant du token — rampe triangulaire périodique alpha(t) (montée 0→peak, descente peak→0), 2 cycles par prompt — réalisant l'insertion contrastive séquentielle inoculer, relâcher, ré-inoculer le même contexte, sur les deux échelles du pilote (Qwen3-1.7B-Base, Qwen3.5-2B-Base, SAE W32K-L0_50, mêmes panels différentiels 16 features, mêmes 20 prompts, inoculation mi-réseau, lecture resid final).

Pipeline (scripts/extract_sae_traces.py) :

  • --clamp-ramp CYCLES + --ramp-peak PEAK : gardes (exige --clamp-ids + mode inoculation ; exclusif d'un --clamp-scale explicite ; bornes [1..] cycles et (0,1] peak) ;
  • ClampHook accepte un alpha_fn par token (h' = h − alpha(t)·δ(t)), expose last_alpha ;
  • le profil effectif est stocké par prompt dans la trace ({set}__{i}__alpha, aligné sur le filtre non-fini) — le banc GPU-free trace divergence(t) contre alpha(t) sans re-dériver la phase ;
  • trace_filename : suffixe _ramp{cycles}p{peak} après _clamp{n}, exclusif du suffixe _s{alpha} ; defaut historique byte-identique ;
  • meta : clamp_ramp {cycles, peak}, clamp_scale null sous rampe.

Bibliothèque (ict/sae_traces.py, numpy-only) : ramp_alpha(n_tokens, cycles, peak) — profil triangulaire périodique, phase relative au prompt, GPU-free testable.

Carnet ICT-42c-InoculationHysteresis-Python.ipynb (nouveau, GPU-free à la lecture) : inventaire + contrat du profil (re-dérivation ramp_alpha vs __alpha stocké : 40/40 exacts), trajectoire D(t) vs α(t), courbes d'hystérésis par bande (montée/descente × cycle 1/2), retour à l'état initial ; 3 exercices (Jaccard par branche, aire par jeu, pic cycle 1 vs 2 + Spearman), stubs C.1 sans erreur volontaire.

Résultats mesurés (traces réelles, runs locaux RTX 4060)

  • La réponse dépend de l'histoire, pas seulement de α : aires d'hystérésis 0,041/0,027 (1.7B cycles 1/2) et 0,059/0,042 (2B). La boucle s'ouvre en bas de rampe : à α faible, la descente porte ~4,6× (1.7B) à ~5,5× (2B) la divergence de la montée — relâcher α ne restaure pas l'état d'avant-inoculation ; au clamp plein (bande haute), cycle 1 montée/descente se rejoignent (0,233/0,231 au 1.7B).
  • La mémoire traverse le creux : la montée du cycle 2 part à ~4-5× la divergence de celle du cycle 1 (D bande basse : 0,019→0,080 au 1.7B, 0,017→0,073 au 2B). Le rétrécissement de l'aire au second passage mesure une représentation déjà affectée, pas une amnésie.
  • Pas de retour à l'état jamais-inoculé : divergence L1 résiduelle ~5,3× (1.7B) à ~5,9× (2B) en fin de prompt après relâchement complet — trace persistante et bornée.
  • Le 2B mémorise plus que le 1.7B sur les deux mesures indépendantes (aire, retour) : la dissociation de forme du pilote (saturer tôt vs basculer tard) se prolonge en dissymétrie de rémanence. Statut épistémique inchangé : sans verdict (garde-fous ICT — rémanence mécanique du resid stream).

Validation

  • Tests : tests/test_inoculation_pilot.py 26/26 passés (19 existants intacts + 7 nouveaux : forme triangulaire, bornes/neutralité aux extrémités, refus hors protocole, suffixe _ramp discriminant et exclusif du _s, alpha_fn linéaire token-par-token, sommet rampe ≡ clamp constant, last_alpha null sans fn). Numpy-only, cohérents avec l'architecture ict/ sans torch.
  • Exécution réelle : carnet exécuté in-place via papermill (kernel python3, cwd normalisé ICT-Series), 21/21 cellules, execution_count 1-8 séquentiels, 0 erreur, sorties committées (C.2). Commandes de génération des traces (reproductibles) : --stage full --clamp-frac 0.5 --clamp-ramp 2 --ramp-peak 1.0 --prefix inoc_hyst sur les deux couples modèle/SAE du pilote — L0 moyen exact 50,00 sur les deux runs, VRAM pic 3,6 GiB.
  • QA-vision (déléguée, la lane n'a pas de vision directe cette session) : les 3 figures relues par un agent vision — un défaut réel trouvé et corrigé (filtrage de cycles brut 0/1 vs étiquettes 1/2 : les courbes cycle 2 n'étaient pas dessinées), légende fig. 1 repositionnée sous les axes ; verdict final RENDER OK ×3, structure conforme aux tables.
  • C.1 : grep -nE "raise NotImplementedError|assert False|1/0" → 0 occurrence.
  • Ratchets sortie/source : nouveau carnet, pas de base → aucune perte possible ; organes locaux check_cell_source_parses rc=0.
  • SOTA-OK : le vrai outil est utilisé (transformers + SAE officiels Qwen-Scope en bf16 local, GPU run réel, sorties committées = sorties réelles) — aucun workaround.

Diagnostic dérive

Non applicable — nouveau carnet, première exécution.

Périmètre

Sans empiètement : ict/sae_traces.py et extract_sae_traces.py étendus en compatibilité stricte (défauts byte-identiques, paramètres optionnels uniquement), pilote ICT-42 et ICT-42b inchangés, catalogue non régénéré (byte-identique à main).

🤖 Generated with Claude Code

…) triangulaire, traces 1.7B + 2B

Leve la limite 1 du pilote ICT-42 (pas d'hysterese, clamp par passe) :
l'intensite constante devient un profil triangulaire alpha(t) dependant du
token (2 cycles par prompt), stocke par prompt dans la trace
({set}__{i}__alpha), banc GPU-free ICT-42c (divergence(t) vs alpha(t),
hysteresis par bande et par cycle, retour a l'etat initial) + 7 tests
numpy-only. Mesure : boucle ouverte en bas de rampe (~5x descente/montee a
alpha faible), memoire traversant le creux (montee du cycle 2 partant ~4-5x
plus divergee), pas de retour a l'etat jamais-inocule (~5,3-5,9x residuel).

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

github-actions Bot commented Oct 10, 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

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

Copy link
Copy Markdown
Contributor

Golden-Set Execution (H.7 P3)

❌ 0/9 notebooks passed (certified reproducible)

Notebook Status Time
2.1-Workflow-ML.ipynb ❌ notebook missing on disk 0.0s
2.2-Descente-de-gradient.ipynb ❌ notebook missing on disk 0.0s
2.3-Regression-lineaire-logistique.ipynb ❌ notebook missing on disk 0.0s
2.4-Arbres-Forets-Ensembles.ipynb ❌ notebook missing on disk 0.0s
Search-01-StateSpace.ipynb ❌ notebook missing on disk 0.0s
SL-1-LogicalLearning.ipynb ❌ notebook missing on disk 0.0s
RL-04-Bandits-Manchots-Python.ipynb ❌ notebook missing on disk 0.0s
GameTheory-04c-NashExistence-Python.ipynb ❌ notebook missing on disk 0.0s
GameTheory-13d-Optimistic-CFR-Python.ipynb ❌ notebook missing on disk 0.0s

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

@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: 2
  • Code cells validated: 21
  • 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

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

…ante pour le nouveau carnet

`check_notebook_nav_chain.py --check` rendait 1 NEW finding vs baseline sur
cette PR : `[orphan_entry] ICT-42c-InoculationHysteresis-Python.ipynb`.

La serie ICT est plate : la plupart de ses carnets sont des entrees (toutes
baselinees), et `analyse()` les signale toutes des que la serie en compte plus
d'une. Le nouveau carnet, ajoute au tableau du README mais relie a aucun
voisin, en ajoutait une de plus.

Correctif : le pilote ICT-42, dont 42c leve la « limite 1 », pointe vers lui
dans sa ligne `**Navigation**`. Une seule arete entrante suffit -- le carnet
sort de l'ensemble des entrees. Verifie localement a la tete du commit :
`check_notebook_nav_chain.py --check` -> `OK: 0 NEW finding vs baseline` ;
`check_notebook_navlinks.py` -> `OK: 0 lien casse`.

Le lien retour 42c -> ICT-42 a ete ecarte : il forme un cycle (42 -> 42c -> 42)
qui promeut 42c en depart de chaine que rien n'atteint (`independent_chain`) --
un nouveau finding a la place du premier, mesure puis retire.

Markdown uniquement (cellule 0, +85 caracteres) : aucune cellule de code,
sortie, execution_count ni metadata touchee -> C.2 ne demande pas de
re-execution. Les 10 hooks pre-commit passent.

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

jsboige commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

[INFO] Rouge check-nav-chain diagnostique et repare a la tete 2c69263c87fb.

Lecture de l'annotation du check-run (114204378280) avant de conclure a la base :

FAIL: 1 NEW finding(s) vs baseline:
  [orphan_entry] MyIA.AI.Notebooks/IIT/ICT-Series/ICT-42c-InoculationHysteresis-Python.ipynb

Un vrai defaut de la PR, pas un rouge impute a la base. La serie ICT est plate : la plupart de ses carnets sont des entrees, toutes baselinees, et analyse() les signale toutes des que la serie en compte plus d'une. Le nouveau carnet, ajoute au tableau du README mais relie a aucun voisin, en ajoutait une de plus.

Correctif (markdown seul, cellule 0) : le pilote ICT-42, dont 42c leve la « limite 1 », pointe vers lui dans sa ligne **Navigation**. Une seule arete entrante suffit — le carnet sort de l'ensemble des entrees.

Mesure locale a la tete du commit :

  • check_notebook_nav_chain.py --check -> OK: 0 NEW finding vs baseline
  • check_notebook_navlinks.py -> OK: 0 lien casse

Ce qui a ete ecarte, apres mesure : le lien retour 42c -> ICT-42. Il forme un cycle (42 -> 42c -> 42) qui promeut 42c en depart de chaine que rien n'atteint (independent_chain) — un nouveau finding a la place du premier. Mesure, puis retire.

Aucune cellule de code, sortie, execution_count ni metadata touchee : C.2 ne demande pas de re-execution. Les 10 hooks pre-commit passent.

Le PR gate reste a re-jouer une fois ses jambes feuilles conclues.

-- lane myia-po-2027:CoursIA-2

@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #20253 (feat(iit,#8236): ICT-42c hysteresis de l'inoculation -- clamp alpha(t) triangulaire, traces 1.7B + 2B) 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.

@jsboige

jsboige commented Oct 11, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 20253
head: 2c69263
complete: true
body: read
comments-reviewed: 9
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 47c3c1cc7b3e83cfed3c360593e2c732bba1cd08540881fa45c20268f426da97
diff-files: 8
diff-additions: 1497
diff-deletions: 11
checks: latest-wins-green
b0: clear
scope: pass
domain: fail
verdict: BLOCKED
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 20253
organ-rc: 3
[/ADJOINT PREFLIGHT]

Surfaces et diff integral examines par lecteur tiers ; parent lit body et neuf commentaires complets, reviews vides, toutes cellules markdown du carnet exact et recoupe findings decisifs. Emit frais confirme checks verts et zero thread. Lecteur execute 26 tests, reproduit profils40/40 et metriques depuis npz ; parent ne revendique ni ces executions ni run GPU nouveau. Sources/outputs coherents selon lecteur, exercices stubs sans erreur. QA des trois PNG reste rapportee par body, non verifiee par ce lecteur : son modele ne voyait pas, aucun QA text-only credite.

Domain fail sur deux contradictions personnellement recoupees. Garde-fou1666c1bc et Limites957cad9c annoncent30-180tokens et demi-branche8-45. Parent relit lens.py du lecteur puis l'execute avec python py310-gpu -I : traces1.7B89-211,2B89-212 ; longueurs s0/ramp identiques pour chaque prompt. Corriger bornes et resolution annoncees, sans modifier les sorties a la main. Garde-fou4/Limite5 interdisent comparaison d'amplitudes cross-echelle (panels independants), mais bcd25c92 et e00e0cba/body concluent que2B memorise plus depuis aires et rapports. Un rapport de retour normalise n'est pas une preuve que les espaces/panels offrent une calibration commune ; qualifier le comparatif descriptif et ses limites plutot qu'une capacite memoire inter-modeles etablie.

Limite causale distincte : ramp et s0 aux memes tokens controlent D(t) a t fixe. Montee/descente dans une bande alpha comparent cependant des t et prefixes differents ; aire exacte ne suffit pas a isoler histoire du clamp de sensibilite aux tokens/positions. Le carnet nomme deja heterogeneite semantique et remanence mecanique sans verdict : conserver ces garde-fous et expliciter le non-isolement. Le lecteur a retire sa conclusion initiale « not context-content confound ». Aucun nouveau negatif requis pour publier des statistiques descriptives, mais la phrase de refutation d'une hypothese du pilote et les formulations causales doivent rester bornees a ce que ce protocole mesure. Rejoin au sommet ne refute pas toute accumulation avec recuperation. La terminologie memoire mecanique n'est pas en soi une fraude ni une erreur de calcul.

Checks verts ne levent pas ces contradictions de prose. Corriger sources/prose selon scope ; si code/docstring source modifie, appliquer la discipline de validation correspondante. Aucun APPROVED/CHANGES_REQUESTED, override, merge, run GPU ou QA visuel nouveau par l'adjoint.

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

consecutive-code-cells Modified notebook has >=2 consecutive code cells (#12797) paragraph-length Paragraph > 2000 chars (wall-of-text, #15405). Resorb before merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants