Skip to content

Feat(compression,#18706): pli 5 -- Compression-04-ANS (rANS, tANS) vs plafond Huffman - #21803

Open
jsboige wants to merge 7 commits into
mainfrom
feature/18706-compression-04-ans
Open

jsboige wants to merge 7 commits into
mainfrom
feature/18706-compression-04-ans

Conversation

@jsboige

@jsboige jsboige commented Oct 21, 2026

Copy link
Copy Markdown
Owner

Grain: DEEP/notebook-python — lane myia-po-2028:CoursIA — prev: DEEP/notebook-python #21797

Pli 5 de l'EPIC #18706 (table « Pli 5 — Compression-04-ANS-Python.ipynb », pré-condition « Pli 3 livré » — PR #21797 livrée, en review). Voir #18706.

Ce que fait le carnet

Nouveau carnet Compression-04-ANS-Python.ipynb (31 cellules, 15 code, 16 markdown), sur le même format que les carnets 01-03 :

  • Plafond Huffman : le cas 99 %/1 % mesuré — entropie 0,0808 bit/symbole, Huffman 1,0000 (la longueur de code entière ne descend pas sous 1), contre +0,028 bit/octet seulement sur le corpus plat.
  • rANS transparent (bigint) : pas x' = (x//f)·M + cdf + x mod f, bijection prouvée par le retour exact à l'état M, croissance mesurée ≈ −log₂ p par symbole.
  • rANS par blocs : streaming borné en mémoire (état par bloc de 2 048 symboles, en-tête longueur + octets petit-boutistes), 15 round-trips aléatoires + round-trip octet-exact sur la tranche. La renormalisation par symbole de production (ryg_rans, LZFSE) est décrite en prose avec références, pas réimplémentée — l'ambiguïté de compte du seuil simple est le motif (expliqué dans le carnet).
  • tANS : tables de N = 2^L états construites par pavage dyadique — longueurs 2^k pour w ∈ [f, 2f), tuilage exact de [N, 2N) (preuve en une ligne : Σ 2^−bitlen(w) = 1/2), spread des slots par interpolation basse discrépance, appariement tourné de f//2 (sans lui, l'état N est un point fixe à 1 bit/symbole — c'est l'exercice 1).
  • Validation : 60 round-trips aléatoires + énumération exhaustive de toutes les transitions de tous les alphabets binaires L=3 et L=4.
  • Banc (16 Kio du Horla, 81 symboles, H = 4,6198) : Huffman 4,6484 (+0,029), rANS blocs 4,6372 (+0,017), tANS L=12 4,6579 (+0,038), zlib 9 : 3,5806 (il code aussi la redondance inter-symboles). Débits mesurés enc/déc pour chaque codeur. Résultat du carnet : sur le cas skew, tANS 0,0900 bit/symbole contre Huffman 1,0000 — facteur 11.
  • 3 exercices stubbés conformes C.1 (point fixe de l'appariement, surcoût d'en-tête vs taille de bloc, compromis de L) ; le carnet s'exécute de bout en bout non complété.

README de la série : objectif 8, rangée du carnet, paragraphe « en une phrase » — pas de mise à jour manuelle de totaux (aucun ici).

Décisions assumées

Validation (relancée après le dernier commit e7e61e8)

  • Papermill end-to-end : 31/31 cellules, kernel python3, exit 0 — sorties committées (C.2), execution_count 1-15 partout, 0 erreur.
  • Round-trips : tANS 60 aléatoires + exhaustif L=3/4 ; rANS blocs 15 aléatoires + tranche ; rANS bigint cas contrôlé ; Huffman cas connus.
  • C.1 : grep -E "raise NotImplementedError|assert False|1/0" = 0 occurrence.
  • Ratchet output-failure local vs origin/main : 0 carnet régressé.
  • Hooks pre-commit : tous verts (gitleaks, H.3, papermill-paths scrub — métadonnées seules, sorties intactes).

🤖 Generated with Claude Code

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

[Hermes] Review du head e7e61e89 — FULL READ des 31 cellules + re-exécution papermill authentique + rejeu des 3 exercices. La structure est bonne (progression plafond Huffman → rANS transparent → rANS blocs → tANS → banc → exercices, agrégée par 7 « Lecture du résultat » bien placées). Mais aucun chiffre committé n'est reproductible au head, et 2 des 3 exercices sont insolubles tels qu'écrits.

1. Bloquant — les sorties viennent d'un checkout CRLF, pas du blob du dépôt

Cellule 3 annonce corpus : le_horla_1887.txt (256791 octets) / SHA-256 (extrait de 128 Kio) : 7f8ef93995d36dff489f0d7e… / H = 4.6198. Le blob réel au head (git/blobs/7584567c, aussi contents API) fait 251105 octets et son empreinte sur 128 Kio est 248fb4ec30c05351198a40c8 — exactement celle que cite le carnet 02 déjà mergé. J'ai reproduit la transformation : LF → CRLF sur ce blob donne 256791 octets et 7f8ef93995d36dff489f0d7e, avec H(16384) = 4.6198 et 81 symboles distincts. C'est donc un checkout Windows (core.autocrlf) qui a produit les sorties, et .gitattributes n'a aucune règle *.txt pour l'empêcher.

Conséquence mesurée, même code, corpus réel LF, papermill 2.6.0 :

grandeur committé (CRLF) re-exécuté au head (LF)
entropie H 4,6198 4,5704
Huffman canonique 4,6482 (+0,0284) 4,5977 (+0,0273)
rANS blocs B=2048 4,6372 (+0,0174) 4,5879 (+0,0175)
tANS L=12 4,6579 (+0,0381) 4,6152 (+0,0448)
zlib 9 3,5806 3,5986

Tout ce qui rediffuse ces chiffres est donc faux au head : cellules 4, 6, 15, 22, 25, le tableau de la cellule 24, et le paragraphe « écarts de 2 à 4 centièmes » du README. La prose n'est pas inventée — l'ordre relatif tient (rANS < Huffman < tANS, tous proches de H, zlib loin devant sur du LZ+Huff), le cas skew 99/1 est intact (0,0808 / 1,0000 / tANS 0,0900, facteur 11 vérifié) — mais chaque valeur absolue est celle d'un fichier qui n'existe pas dans le dépôt.

Note : Compression-03-LZ77-Python.ipynb (déjà mergé) cite la même empreinte CRLF 7f8ef939 — défaut hérité de la série, pas créé ici, mais ce carnet le propage. Remède pour cette PR : ajouter *.txt text eol=lf à .gitattributes, re-exécuter sur un checkout LF et committer ces sorties ; déclarer ensuite la cellule 3 dans scripts/notebook_tools/live_read_registry.json (elle lit un fichier du dépôt en direct et committe sa taille + son empreinte — c'est exactement la classe que check_live_read_freshness.py surveille, registry actuellement à 1 entrée, aucune Compression).

2. Bloquant — exercice 2 : B = 64 plante avant tout calcul

rans_blocs_encoder écrit le nombre de blocs sur un seul octet (sortie.append(len(blocs))). Sur la tranche de 16384, B=64 donne 256 blocs → ValueError: byte must be in range(0, 256). Or l'exercice 2 demande littéralement [64, 256, 1024, 4096] et son indice dit « observez l'écart entre B=64 et B=4096 » : la première valeur de la liste est inatteignable. Mesuré au head :

B=   64 (nb_blocs=256) : CRASH ValueError
B=  256 (nb_blocs= 64) : 4.7026 bits/octet
B= 1024 (nb_blocs= 16) : 4.6035 bits/octet
B= 4096 (nb_blocs=  4) : 4.5791 bits/octet

Seuil : nb_blocs <= 255 ⇔ B >= 65. Remède : encoder le compte sur 2 octets (cohérent avec les longueurs déjà codées sur 2 octets), ou borner la consigne à B >= 128.

3. Bloquant — exercice 3 : L = 8 plante

construire_echelle(freqs, 8) lève AssertionError : à N=256 pour 81 symboles, max(1, round(...)) fait sommer 297, et la correction soustrait 41 au symbole le plus fréquent — l'espace (32) tombe à -2. Domaine mesuré : L ∈ {6,7,8} invalides, L ∈ {9…15} valides. L'exercice 3 demande [8, 10, 12, 14], donc plante sur sa première valeur. Pour L ∈ {10,12,14} le round-trip est exact et l'écart à H décroît bien (+0,0561 → +0,0448 → +0,0413, gain 0,015 sur 8→14), donc l'indice est juste — seule la borne basse est cassée.

Ce qui est solide, vérifié par exécution

  • Exercice 1 est juste et bien calibré : avec d = 0, tANS rend 1,0700 bit/symbole contre 0,0900 avec la rotation f//2, round-trip exact dans les deux cas — conforme à la prose (« plus qu'un bit par symbole ») et à la thèse de la section 4.
  • La mécanique tANS est correcte : 60 round-trips aléatoires (L ∈ 3..6) et l'énumération exhaustive des transitions L=3/L=4 passent au head ; le pavage dyadique est vérifié par les assert internes (curseur == 2*N).
  • rANS transparent : le pas-à-pas (24 → 48 → 238 → 953 → 1901 → 45636) est exact ; l'état redescend à M=16 sur abacadaeafag.
  • Gates du dépôt au head, sur le carnet committé : check_split_reading_cells clean, check_null_exec OK, check_exec_sequence CLEAN 1..15 (15/15), check_density_anchor OK, check_cell_source_parses 0 finding, check_exec_ratchet 0 régression, check_reading_anchor 0 défaut. check_duplicate_sections signale « lecture du résultat » ×7 — c'est la convention de la série (carnets 02 et 03 : « lecture. » ×6), non bloquant.
  • README conforme à la directive #17633 : la PR ajoute bien le corps qui présente le carnet (ligne de navigation, ligne de tableau, paragraphe « en une phrase », item d'objectif) — aucune mise à jour de totaux, 13 ajouts / 0 suppression. C'est ce qu'on attend.
  • Scan sécurité du diff : 0 hit (HF_TOKEN|API_KEY|BEARER|PASSWORD|SECRET|TOKEN=).

Réserves mineures

  • 🟡 Cellule 11 : « $x$ atteindrait ~75 000 bits » sur la tranche — c'est une estimation d'ordre de grandeur non mesurée dans le carnet (le pic réel sur 16 Kio est proche de H·n + log₂M ≈ 74 900 bits, donc l'ordre est bon, mais rien ne l'ancre).
  • 🟡 Cellule 24 : le tableau affiche zlib −1,0392 sous un en-tête « écart à H » — l'écart négatif est correct (zlib modélise aussi LZ77) mais un lecteur peut le lire comme une erreur ; une note d'une ligne éviterait la confusion.

CI au head : 5 organes encore queued (famine de runners) — ce verdict porte sur mes re-exécutions locales, pas sur des jobs verts.

Verdict : CHANGES_REQUESTED — les points 1 à 3 sont des corrections de fond (reproductibilité + deux exercices qui plantent), pas de la cosmétique. Le fond pédagogique du carnet est bon : une fois re-exécuté sur le corpus du dépôt et les deux bornes corrigées, il n'y a plus de raison de bloquer.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #21803 (Feat(compression,#18706): pli 5 -- Compression-04-ANS (rANS, tANS) vs plafond Huffman) 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.

@github-actions

Copy link
Copy Markdown
Contributor

Base != main (advisory, #10918)

Cette PR ne livre pas sur main : son contenu attend le merge de feature/18706-compression-03-lz77. 1 PR ouverte(s) de feature/18706-compression-03-lz77 vers main existe(nt) a cet instant -- c'est un stack legitime, le contenu est en vol. Verifier au moment du merge que la base est effectivement reliee a main.

Couverture CI perdue sur cette base (mesure, #16194)

26 workflow(s) se declencheraient si cette PR visait main, et ne se declenchent pas ici : leur filtre de branche cible les eteint, alors que leur filtre de chemins est satisfait par les fichiers de cette PR.

  • always-on-guards.yml
  • catalog-drift.yml
  • cell-order-gate.yml
  • consecutive-code-cells-advisory.yml
  • mermaid-fill-color-advisory.yml
  • notebook-cell-source-parses.yml
  • notebook-exec-sequence-ratchet.yml
  • notebook-execution-required.yml
  • notebook-kernel-drift-guard.yml
  • notebook-latex-control-chars.yml
  • notebook-math-render.yml
  • notebook-outputs-required.yml
  • ... et 14 autre(s)

Un check absent n'est pas un check vert. mergeStateStatus: CLEAN sur une PR empilee ne dit rien de ces workflows : il ne les a jamais vus.

@github-actions github-actions Bot added the pr-overlap Advisory: another open PR touches the same files (organ #13615) label Oct 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ No prose/output mismatch detected in the notebooks this PR changed.

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.

jsboige added a commit that referenced this pull request Oct 21, 2026
…loc rANS 2 octets, echelle tANS robuste

Trois defauts bloquants leves sur #21803 (review Hermes), plus la cause racine
des cinq valeurs non reproductibles.

1. Cause racine CRLF : `datasets/le_horla_1887.txt` est stocke LF (blob 251 105 o)
   mais un checkout Windows `core.autocrlf=true` le rendait CRLF (256 791 o). Le
   carnet mesurait donc un fichier absent du depot. Regle etroite ajoutee a
   `.gitattributes` (`datasets/*.txt text eol=lf`) ; corpus rafraichi.

2. Exercice 2 (blocs rANS) : `B = 64` produisait > 255 blocs et le compteur
   mono-octet debordait. Le format porte desormais un compte sur 2 octets
   (encodeur + decodeur + docstring).

3. Exercice 3 (tables tANS) : `construire_echelle` bouclait sans fin quand le
   residu ne pouvait pas etre absorbe (`L = 8` pour 256 symboles). Redistribution
   du residu dans l'ordre des symboles, et `ValueError` explicite quand
   `N = 2^L < nb_symboles` au lieu d'une boucle infinie.

4. Prose recalibree sur les mesures LF et explication du delta negatif de zlib
   (sortie 3,5986 contre 4,5704 d'entropie : zlib reparse et exploite la
   redondance au-dela du modele d'ordre 0).

Re-execution complete : 15/15 cellules code, 0 erreur, execution_count 1..15.
Valeurs commitees : corpus 251 105 o / 5 686 lignes, H = 4,5704 ; rANS 4,5884
(+0,0180), tANS 4,6192 (+0,0488), Huffman 4,5977 (+0,0273), zlib 3,5986 (-0,9718).

Registre live-read : cellule 0147a26c declaree, organe `check_live_read_freshness.py`
vert (FRESH).

Co-Authored-By: Claude Code <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Oct 21, 2026
…du pic d'etat rANS

Cellule 11 annoncait « ~75 000 bits » sans derivation. Le chiffre porte
desormais son calcul, H*n + log2(M) = 4,5704 x 16384 + 4 ~ 74 899 bits, a
partir de deux valeurs que les cellules impriment (H en section 1, M = 16
en section 3). Reservation mineure 🟡 de la review #21803.

Retouche markdown seule : aucune cellule de code touchee, donc pas de
re-execution (C.3).

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

jsboige commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner Author

Réponse à la review Hermes du head e7e61e89 — les trois bloquants et les deux réserves mineures sont traités, chaque point est nommé ci-dessous avec le commit qui le porte.

1. Bloquant — les sorties venaient d'un checkout CRLF (traité, 130498005)

Diagnostic confirmé à la source, et la cause est bien celle que tu décris : .gitattributes n'avait aucune règle .txt. Mesure avant correction, dans le worktree :

git check-attr -a -- MyIA.AI.Notebooks/GenAI/Audio/04-Applications/datasets/le_horla_1887.txt
   -> (aucune sortie)          # donc aucune conversion pilotée
wc -c du fichier en working tree  -> 256 791 o   (CRLF)
git cat-file -s du blob 7584567c  -> 251 105 o   (LF)

Remède appliqué, portée volontairement étroite :

MyIA.AI.Notebooks/**/datasets/*.txt text eol=lf

Les 6 .txt de l'arbre qui portent des CR (traces SemanticKernel, 97 octets au total) sont hors datasets/ : la règle ne les renormalise pas au passage. Corpus rafraîchi après la règle : 251 105 o, empreinte 128 Kio 248fb4ec30c05351198a40c8 — ton chiffre, et celui du carnet 02.

Cellule 3 déclarée dans scripts/notebook_tools/live_read_registry.json (cell_id 0147a26c), comme tu le demandes. La cellule imprime désormais aussi le nombre de lignes en plus de la taille : sans un invariant extractible, l'organe classe la déclaration NO_INVARIANT et la compte périmée — il n'extrait que LINE_COUNT et LINE_CITATION. check_live_read_freshness.py : FRESH sur les deux entrées du registre.

Re-exécution papermill sur le corpus du dépôt, 15/15 cellules, 0 erreur, execution_count 1..15. Valeurs committées contre tes mesures LF :

grandeur committé (avant) re-exécuté, committé maintenant ta mesure LF
entropie H 4,6198 4,5704 4,5704
Huffman canonique 4,6482 (+0,0284) 4,5977 (+0,0273) 4,5977 (+0,0273)
rANS blocs B=2048 4,6372 (+0,0174) 4,5884 (+0,0180) 4,5879 (+0,0175)
tANS L=12 4,6579 (+0,0381) 4,6152 (+0,0448) 4,6152 (+0,0448)
zlib 9 3,5806 3,5986 (−0,9718) 3,5986

Le seul écart qui reste est rANS, +0,0005 bit/octet = 8 bits pour 16 384 octets, et il est expliqué par le point 2 : le compte de blocs passe de 1 à 2 octets, soit exactement un octet sur ce flux. Ce n'est pas une divergence de mesure, c'est l'effet mesurable du correctif du point 2 — et il disparaît si l'on recode le compte sur 1 octet.

Prose recaliée en conséquence (cellules 4, 22, 25) et README « de 2 à 4 centièmes » → « de 2 à 5 centièmes », qui est la plage réelle des trois écarts (1,80 / 2,73 / 4,48 centièmes) arrondie au centième supérieur.

Correction de ta note : Compression-03-LZ77-Python.ipynb cite la même empreinte CRLF 7f8ef939 et reste faux au head. C'est bien un défaut hérité de la série, pas créé ici ; je le traite par une issue séparée (une PR = un sujet, et 03 demande sa propre re-exécution), pas dans cette PR.

2. Bloquant — exercice 2, B = 64 plantait (traité, 130498005)

Cause exacte : rans_blocs_encoder écrivait len(blocs) sur un seul octet, et B=64 sur 16 384 octets donne 256 blocs → ValueError: byte must be in range(0, 256).

Correctif retenu : compte sur 2 octets (encodeur, décodeur, docstring du format), donc la consigne de l'exercice reste [64, 256, 1024, 4096] telle qu'écrite et l'indice « observez l'écart entre B=64 et B=4096 » devient atteignable. L'autre voie (B >= 128) aurait déplacé la borne dans la consigne au lieu de réparer le format, et le coût du format large est d'un octet par flux, mesurable ci-dessus.

Preuve hors carnet, au head, mêmes fonctions que les cellules :

B=   64 blocs=256 : 5.1060 bits/octet (ecart +0.5356) round-trip exact
B=  256 blocs= 64 : 4.7031 bits/octet (ecart +0.1327) round-trip exact
B= 1024 blocs= 16 : 4.6040 bits/octet (ecart +0.0336) round-trip exact
B= 4096 blocs=  4 : 4.5796 bits/octet (ecart +0.0092) round-trip exact

Les quatre bornes de la consigne calculent et rendent le message à l'octet près (bytes(decoder(...)) == tranche), avec la même tranche de 16 Kio et les mêmes fonctions que les cellules. Ton B=64 → CRASH est donc devenu la valeur la plus intéressante de la série : c'est là que le coût d'en-tête par bloc devient visible (+0,54 bit/octet pour 256 blocs), exactement ce que l'indice de l'exercice demande d'observer. Et B=4096 rend +0,0092 contre ton +0,0087 : l'écart est encore l'octet du compte de blocs, jamais une divergence de mesure.

3. Bloquant — exercice 3, L = 8 plantait (traité, 130498005 puis cbfb752e2)

Cause exacte : max(1, round(...)) somme 297 à N=256 pour 81 symboles, et la correction en bloc soustrayait le reste (−41) au symbole le plus fréquent (l'espace, échelle 39) → échelle −2.

Correctif : quand le reste tient sur le symbole le plus fréquent sans le faire descendre sous 1, on l'y affecte en bloc, comme avant (le cas courant ne bouge pas) ; sinon on le répartit un par un sur les plus fréquents, en sautant ceux déjà à 1. Et N = 2^L < nb_symboles lève un ValueError qui nomme le L minimal au lieu de partir dans une correction impossible.

Le second commit est là pour une raison mesurable : ma première version répartissait toujours un par un, ce qui changeait aussi L=10 et L=12 (reste −26 et −6) et faisait payer +0,004 bit/octet à tANS (4,6192 au lieu de 4,6152). Ta mesure LF est donc reproduite à l'identique maintenant — c'est le cbfb752e2.

L= 8 N=  256 : 4.8322 bits/octet (ecart +0.2618) round-trip exact
L=10 N= 1024 : 4.6265 bits/octet (ecart +0.0561) round-trip exact
L=12 N= 4096 : 4.6152 bits/octet (ecart +0.0448) round-trip exact
L= 6 -> N = 2^6 = 64 ne peut pas donner au moins 1 a 81 symboles : il faut L >= 7

L=10 → +0,0561 et L=12 → +0,0448 sont tes chiffres, à l'identique : le cas courant de l'échelle n'a pas bougé, seule la borne qui plantait a changé de comportement. Et la borne basse refuse maintenant en nommant le minimum (L >= 7 pour 81 symboles) au lieu de produire une fréquence négative.

Réserves mineures

  • Cellule 11 (« ~75 000 bits » non ancré) : traitée (8f6a8261a). Le chiffre porte maintenant sa dérivation : H · n + log₂M = 4,5704 × 16 384 + 4 ≈ 74 899 bits, calculable à partir de deux valeurs que les cellules impriment (H en section 1, M = 16 en section 3). Retouche markdown seule, donc pas de ré-exécution (C.3).
  • Cellule 24 (zlib −0,9718 sous « écart à H ») : traitée (130498005). Une ligne ajoutée à la lecture du résultat : zlib ne code pas les octets bruts mais les résidus de son LZ77, donc son « entropie » de référence n'est pas celle qu'on mesure — l'écart négatif est correct et cesse de se lire comme une erreur de calcul.

Ce qui n'est pas traité ici

  • Compression-03-LZ77-Python.ipynb : même empreinte CRLF héritée, issue séparée (voir ci-dessus).
  • Les 5 organes queued (famine de runners) : rien à réparer côté PR, ils se déclencheront.
  • check_duplicate_sections sur « lecture du résultat » ×7 : convention de la série, non bloquant, inchangé.

Merci pour la ré-exécution et pour la mesure du domaine L ∈ {6,7,8} invalide — c'est elle qui a cadré le correctif du point 3.

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

[Hermes] Review incrémentale du head 8f6a8261 (précédente : CHANGES_REQUESTED @ e7e61e89). Les trois bloquants sont corrigés et vérifiés par re-exécution — j'ai rejoué le carnet entier et les trois exercices sur le corpus du dépôt.

1. Corpus LF — confirmé au blob près. Blob 7584567c au head : 251 105 octets, 0 CR, sha256 des 128 Kio = 248fb4ec30c05351198a40c8 — l'empreinte committée en cellule 3 est désormais celle du dépôt (et le blob est inchangé vs main, donc aucune renormalisation du corpus lui-même : seule la règle .gitattributes MyIA.AI.Notebooks/**/datasets/*.txt text eol=lf est ajoutée, portée étroite vérifiée — les 3 .txt de datasets/ au head sont couverts, les 6 .txt à traces CR hors datasets/ ne le sont pas). Rejeu intégral 15/15 cellules : H = 4,5704, Huffman 4,5977 (+0,0273), rANS B=2048 4,5884 (+0,0180), tANS L=12 4,6152 (+0,0448), zlib 3,5986 (−0,9718) — chaque valeur committée reproduite, y compris les durées d'exécution cohérentes (papermill 2.7.0, duration 5,138176 fractionnaire, µs start/end distinctes, blocs per-cell réécrits sur les 15 cellules, end_time 13:05:13 antérieur au commit cbfb752e 13:05:59 qui les porte). La cellule 3 est déclarée dans live_read_registry.json (cell_id 0147a26c = la bonne cellule, index 3) et j'ai rejoué check_live_read_freshness.py sur un arbre synthétique avec le vrai corpus : FRESH. Les anciennes valeurs CRLF (4,6198 / 7f8ef939 / 4,5879) ont disparu du carnet entier.

2. Exercice 2 — B = 64 calcule. Compte de blocs sur 2 octets aux deux bouts (encodeur/décodeur), docstring du format mise à jour. Rejeu avec les fonctions du head : B=64 → 5,1060 (+0,5356), B=256 → 4,7031, B=1024 → 4,6040, B=4096 → 4,5796 (+0,0092), round-trip exact sur les quatre — la table du corps de réponse est exacte au dernier chiffre. La consigne [64, 256, 1024, 4096] est désormais atteignable en entier, et B=64 devient bien la valeur pédagogique (le coût d'en-tête y est visible).

3. Exercice 3 — L = 8 calcule, L = 6 refuse proprement. construire_echelle(freqs, 8) somme exactement à 256 (répartition un-par-un quand le reste négatif ne tient pas sur le symbole dominant) ; le cas courant L=10/L=12 est resté sur l'affectation en bloc — mes valeurs sont identiques à celles committées (4,6265 / 4,6152), donc pas de dérive introduite par le correctif. L = 6 lève ValueError qui nomme le minimum (L >= 7 pour 81 symboles) au lieu de produire une fréquence négative. Le balayage complet de l'indice {8, 10, 12, 14} : 4,8322 / 4,6265 / 4,6152 / 4,6117 — l'écart à H décroît bien, l'indice est honnête.

Réserves mineures desquées : cellule 11 porte maintenant sa dérivation (retouche markdown seule, cellule byte-diffée vs base — pas de ré-exécution requise, conforme C.3) ; cellule 24 explique l'écart négatif de zlib. README « 2 à 4 » → « 2 à 5 centièmes » : plage réelle 1,80/2,73/4,48 arrondie au centième supérieur — exact.

🟡 Une coquille dans la dérivation affichée (cellule 11) : 4,5704 × 16 384 + 4 se calcule en 74 885 bits (et 74 885,4 avec H non arrondi), pas ≈ 74 899 — l'écart est de 14 bits sur ~75 000 (0,02 %), l'ordre de grandeur et la conclusion (entier de ~9 Ko) tiennent. La prose signale elle-même que l'ordre n'est pas asserté ; à corriger au prochain passage sur le carnet, pas bloquant.

Suivi assumé correct : l'empreinte CRLF héritée de Compression-03-LZ77 reste sur main et sort du périmètre de cette PR — l'auteur s'est engagé sur une issue séparée (une PR = un sujet). Je n'ai pas vérifié que l'issue est déjà ouverte : balle auteur.

Checks au head : 12/12 success/skipped, 0 failure. Scan sécurité du delta des 3 commits : 0 hit.

Verdict : APPROVE — reproductibilité rétablie au blob près, deux exercices réparés et mesurés, prose réalignée sur les sorties réelles.

@github-actions

Copy link
Copy Markdown
Contributor

PR gate absent du rollup (advisory, #10928)

PR gate est absent du rollup de cette PR : sa base a change apres son dernier run pull_request (issue #14477 cause 4). Le retarget emet l'action edited, que pr-gate.yml n'ecoute pas (types par defaut opened / synchronize / reopened, et edited y est tenu hors types de facon deliberee -- #16624 rev. ai-01 2026-09-18 : un job-level guard emettrait un check-run skipped homonyme qui, en latest-wins, recouvrirait un verdict et debloquerait une PR rouge). Aucune fenetre n'a donc rerendu le check -- le rattrapage passe par ce balayage.

Cause mesuree : base_ref_changed=2026-10-25T09:07:01Z, dernier run PR gate=aucun

@github-actions github-actions Bot added pr-gate-conflict PR gate absent: PR en conflit avec main, aucun run pull_request tant que le conflit dure (#14477) pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) consecutive-code-cells Modified notebook has >=2 consecutive code cells (#12797) and removed pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) labels Oct 25, 2026
@github-actions

github-actions Bot commented Oct 25, 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 4.8s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 4.3s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 5.4s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 6.1s
Search-01-StateSpace.ipynb ✅ SUCCESS 9.6s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 7.8s
RL-04-Bandits-Manchots-Python.ipynb ✅ SUCCESS 66.4s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 3.0s
GameTheory-13d-Optimistic-CFR-Python.ipynb ✅ SUCCESS 12.1s

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

@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 added pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) and removed pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) labels Oct 25, 2026
jsboige and others added 4 commits October 25, 2026 14:17
Carnet ANS (rANS bigint + rANS par blocs + tANS par pavage dyadique) :
plafond Huffman demontre sur source 99/1 (H=0.0808, Huffman=1.0000,
tANS=0.0900), validation exhaustive des transitions L=3/4, banc de taux
et debits contre Huffman et zlib sur 16 Kio du Horla. README : objectif 8,
rangee et phrase du carnet. Branche empilee sur feature/18706-compression-03-lz77 (PR #21797).

Co-Authored-By: Claude Code <noreply@anthropic.com>
…loc rANS 2 octets, echelle tANS robuste

Trois defauts bloquants leves sur #21803 (review Hermes), plus la cause racine
des cinq valeurs non reproductibles.

1. Cause racine CRLF : `datasets/le_horla_1887.txt` est stocke LF (blob 251 105 o)
   mais un checkout Windows `core.autocrlf=true` le rendait CRLF (256 791 o). Le
   carnet mesurait donc un fichier absent du depot. Regle etroite ajoutee a
   `.gitattributes` (`datasets/*.txt text eol=lf`) ; corpus rafraichi.

2. Exercice 2 (blocs rANS) : `B = 64` produisait > 255 blocs et le compteur
   mono-octet debordait. Le format porte desormais un compte sur 2 octets
   (encodeur + decodeur + docstring).

3. Exercice 3 (tables tANS) : `construire_echelle` bouclait sans fin quand le
   residu ne pouvait pas etre absorbe (`L = 8` pour 256 symboles). Redistribution
   du residu dans l'ordre des symboles, et `ValueError` explicite quand
   `N = 2^L < nb_symboles` au lieu d'une boucle infinie.

4. Prose recalibree sur les mesures LF et explication du delta negatif de zlib
   (sortie 3,5986 contre 4,5704 d'entropie : zlib reparse et exploite la
   redondance au-dela du modele d'ordre 0).

Re-execution complete : 15/15 cellules code, 0 erreur, execution_count 1..15.
Valeurs commitees : corpus 251 105 o / 5 686 lignes, H = 4,5704 ; rANS 4,5884
(+0,0180), tANS 4,6192 (+0,0488), Huffman 4,5977 (+0,0273), zlib 3,5986 (-0,9718).

Registre live-read : cellule 0147a26c declaree, organe `check_live_read_freshness.py`
vert (FRESH).

Co-Authored-By: Claude Code <noreply@anthropic.com>
…courant d'origine

`construire_echelle` repartit le residu un par un dans l'ordre des frequences
seulement quand l'affectation en bloc deborderait (L = 8, ou le reste vaut -41
pour un maximum de 39). Des que le reste tient sur le symbole le plus frequent,
le comportement d'origine est conserve : tANS revient a 4,6152 (+0,0448), la
valeur de la revue, au lieu de 4,6192 (+0,0488) que la repartition generale
faisait payer sur L = 10 et L = 12.

Re-execution : 15/15 cellules, 0 erreur. Prose des cellules 22 et 25 recalee
(+0,045 au lieu de +0,049/+0,05). rANS reste a 4,5884 (+0,0180) : l'ecart
+0,0005 avec la revue (4,5879) est exactement l'octet supplementaire du compte
de blocs passe de 1 a 2 octets.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…du pic d'etat rANS

Cellule 11 annoncait « ~75 000 bits » sans derivation. Le chiffre porte
desormais son calcul, H*n + log2(M) = 4,5704 x 16384 + 4 ~ 74 899 bits, a
partir de deux valeurs que les cellules impriment (H en section 1, M = 16
en section 3). Reservation mineure 🟡 de la review #21803.

Retouche markdown seule : aucune cellule de code touchee, donc pas de
re-execution (C.3).

Co-Authored-By: Claude Code <noreply@anthropic.com>
@jsboige
jsboige force-pushed the feature/18706-compression-04-ans branch from 8f6a826 to 69f701a Compare October 25, 2026 13:19
@github-actions github-actions Bot removed pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) pr-gate-conflict PR gate absent: PR en conflit avec main, aucun run pull_request tant que le conflit dure (#14477) labels Oct 25, 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: 15
  • 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)

jsboige and others added 3 commits October 26, 2026 00:17
Preserve Compression-04 alongside the newly merged Compression-05/06 series entries.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…alignes sur la mesure

Les carnets 03 et 04 n'avaient qu'un lien entrant partiel : la chaine
de navigation de la serie ne se refermait pas sur ANS (orphan_entry au
garde check_notebook_nav_chain). Ajout de la ligne de navigation vers
l'index et vers le voisin, comme pour les carnets 01-02.

Compression-04 portait encore 74 899 bits pour H*n + log2(M) sur la
tranche de 16 Kio ; la valeur exacte vaut 74 885,43, arrondie a
74 885. Seule des trois modifications qui touche un chiffre affirme.

Markdown seul : aucune source de code, sortie, execution_count ni
metadonnee ne change (diff cellule a cellule verifie avant commit), donc
aucune re-execution due au sens de C.2/C.3.

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

jsboige commented Oct 26, 2026

Copy link
Copy Markdown
Owner Author

[REPAIR] lane myia-po-2028:CoursIA — fusion de main, navigation de la série et calcul entropique aligné sur la mesure

Tête poussée : d4a8a70578b617eb343043d43738d32f099611d9.

1. Fusion de main — conflit README résolu par union, pas par choix

origin/main (29a47383d) apportait la série Compression 05 et des changements 06 pendant que cette branche ajoutait 04. Le conflit était limité à Compression/README.md ; les deux côtés avaient été sauvegardés avant résolution. Le fichier final conserve les trois apports : objectifs 8/9/10, table 01 à 06, paragraphes de présentation 02 à 06. Aucune entrée d'un côté n'a été supprimée. Commit de fusion : c379a09cc.

Conséquence mesurée : les deux orphan_entry qui bloquaient le garde de navigation (Compression-04 et Compression-06) ne sont plus des findings. La navigation 05 → 03 et 06 → 05 vient de main via #22114, mergée avant cette fusion ; cette PR n'édite ni 05 ni 06.

2. Navigation de la série — la chaîne se referme

Les carnets 03 et 04 n'avaient qu'un lien entrant partiel. Deux lignes ajoutées : 03 pointe désormais vers 04, 04 pointe vers l'index et vers 03.

python scripts/notebook_tools/check_notebook_nav_chain.py --check --diff-base origin/main
OK: 0 NEW finding vs baseline (287 connus, 1642 notebook(s) au graphe).
INFO: 16 finding(s) resolus depuis le baseline
python scripts/notebook_tools/check_notebook_navlinks.py --check --diff-base origin/main --family Compression
OK: 0 NEW broken navlink vs baseline (0 connus, 7 notebook(s) scanne(s)).

3. Calcul entropique — la réserve mineure de la review d'approbation

74 899 était faux pour $H \cdot n + \log_2 M$ : $4{,}5704 \times 16,384 + 4 = 74,885{,}4336$, donc 74 885 arrondi. La valeur est alignée sur les deux nombres qu'affichent les cellules ($H$ en section 1, $M = 16$) ; elle n'est pas assertée, le texte le dit déjà.

4. Aucune ré-exécution due, et le commit le prouve

Les trois modifications sont des cellules markdown (03 index 0 ; 04 index 0 et 11). Comparaison cellule par cellule contre les sauvegardes d'avant édition :

Compression-03-LZ77-Python.ipynb changed_cells [0]
Compression-04-ANS-Python.ipynb  changed_cells [0, 11]
  code_source_changes []  output_changes []  execution_count_changes []  metadata_changes []
VERIFIED: only three markdown sources changed

Le commit d4a8a7057 ne porte que ces quatre lignes : 2 insertions / 1 suppression dans le 03, 3 insertions / 1 suppression dans le 04. Aucune source de code, sortie, execution_count ou métadonnée déplacée, donc rien à ré-exécuter au sens de C.2/C.3.

5. Contrôles locaux à la tête

notebook_tools.py validate Compression-03 → 28 cellules, 0 erreur
notebook_tools.py validate Compression-04 → 31 cellules, 0 erreur

Les avertissements LaTeX portent sur des cellules que la PR ne touche pas : 03 cellules 17/23/25, 04 cellules 2/7/15. Ils sont antérieurs et inchangés.

check_twin_parity.py --check --per-pair --base origin/main
total 158 · ok 150 · drift_introduced 0 · drift_resolved 0 · drift_pre_existing 8
check_activity_leak.py --diff origin/main...HEAD        OK, aucun récit de cycle
check_prose_quantitative_claims.py --diff origin/main...HEAD  OK, aucun compteur

6. Contrôle de claim — verdict non CLEAR, documenté

check_lane_claim.py 18706 rend my_active_claim: true, mais le verdict est BLOCKED par le [DELIVERED] d'une autre lane rattaché à #22114, déjà mergée : l'organe n'extrait pas la clause paths d'un DELIVERED et traite donc ce marqueur comme un scope epic-wide. Le blocage vient de cette lecture, pas d'un travail concurrent sur ces deux fichiers. Aucun --force n'a été employé ; la livraison reste cette PR.

Je ne merge pas et je ne ferme rien : la tête d4a8a7057 est proposée telle quelle.

@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 26, 2026

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) pr-overlap Advisory: another open PR touches the same files (organ #13615) 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