Skip to content

fix(tooling,#17729): scan_diff ne compte plus les SORTIES de cellule comme de la prose - #17732

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/17729-prose-counts-diff-outputs
Sep 25, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/17729-prose-counts-diff-outputs

Conversation

@jsboige

@jsboige jsboige commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2024:CoursIA-2 — prev: LIGHT/docs #17722

Le defaut : le mode diff compte les SORTIES de cellule comme de la prose

scan_diff (scripts/notebook_tools/check_prose_quantitative_claims.py) parcourt le diff ligne par ligne. Il exclut bien les cles "output_type" / "execution_count" / "outputs", mais pas les charges utiles de sortie : ce sont des chaines nues (" \" Angel.lean 65 lignes\\n\",") qui passent le filtre '"source"' not in line and not body.startswith('"'). Le mode diff ne voit pas les cellules, donc il ne peut pas attribuer une ligne a un type de cellule.

Or la doctrine du module, dans son propre en-tete, declare ce cas legitime :

Une cellule code qui compte et affiche est la bonne facon de porter un chiffre : il se recalcule a chaque execution. On ne la regarde pas.

Mesure sur deux PRs de cette lane, tete exacte :

PR Tete Finding de l'organe source de cellule outputs
#16987 d13f0c5c45 Lean-16b-...-Lean.ipynb (80) 0 77 dans cell[3]
#16974 fb98304d06 Lean-16f-...-Theorem.ipynb (1) 0 cell[16]

Les valeurs sont fraiches, pas un artefact de re-encodage : Lean-16b porte 28 de ces compteurs dans ses sorties sur main, 77 sur la tete — la cellule de comptage a ete re-executee. Depuis #17645, ce check est bloquant : deux PRs dont aucune prose ne portait de compteur etaient rouges.

Correctif : la carte des blocs outputs, croisee avec le numero de ligne du fichier nouveau

Une ligne de prose et une charge utile de sortie sont, ligne a ligne, indiscernables. Mais "source" et "outputs" sont a la meme profondeur dans le pretty-print nbformat, et le bloc se referme sur une ligne d'indentation egale a celle de sa cle :

   "outputs": [            <- ouverture, indentation 3
     {                     <- dedans
      "text": [
       "  Angel.lean   65 lignes\n",   <- dedans
      ]
     }
   ],                      <- fermeture, indentation 3
   "source": [
    "print(...)\n",        <- hors du bloc
   ],
  • _ipynb_output_lines(rel) calcule une fois par fichier l'ensemble des lignes situees dans un bloc outputs. Le \s*$ de OUTPUTS_OPEN_RE est load-bearing : "outputs": [] (cellule jamais executee) se referme sur sa propre ligne, l'ouvrir ferait avaler tout le reste du fichier.
  • scan_diff suit le numero de ligne du fichier nouveau depuis les en-tetes de hunk (@@ -a,b +c,d @@ ; en --unified=0 le corps du hunk ne porte que les lignes ajoutees, donc la 1re ligne + est la ligne c) et saute les lignes cartographiees.

La prose markdown vit aussi sous "source" : elle reste flagee, scan_diff ne la touche pas.

Acceptance mesuree

Tete Avant Apres
#16987 d13f0c5c45 [REFUS] 80 [REFUS] 3
#16974 fb98304d06 [REFUS] 1 [OK] aucun compteur

Les 3 residuels de #16987 sont un VRAI positif, et c'est l'argument que le correctif ne desarme rien : la ligne 2443 du fichier nouveau est une prose markdown ajoutee par la branche (accents restaures vs main), qui affirme 5 cells, 48 cells, canon de Gosper 36 cells. Elle doit rester rouge. Le compte de sorties legigimes sautees sur cette tete est exactement 77 (80 = 77 + 3).

L'issue #17729 annoncait « 80 -> 0 » comme critere de sortie. Le chiffre mesure est 3, et les trois sont des compteurs de prose reels : le critere tel qu'ecrit etait trop fort, la mesure le corrige.

Tests

scripts/notebook_tools/tests/test_check_prose_quantitative_claims.py — 26 passed :

  • test_ipynb_output_lines_maps_payloads_not_sources : la carte distingue source markdown / source code / charge utile, et ne se referme pas sur "outputs": [] (la cellule suivante doit rester hors du bloc).
  • test_scan_diff_skips_output_payloads_but_flags_source_prose : depot git jetable dans tmp_path (hors depot de travail), core.autocrlf=false pour que l'arbre et le blob soient comparables octet a octet. Frontiere mesuree sur le meme compteur : ajoute en charge utile de sortie = 0 finding ; ajoute en prose markdown = 1 finding.

Controle negatif (le test doit echouer sur la version d'avant, sinon il ne verrouille rien) : la meme suite jouee contre le module de main rend 2 failed, 24 passed, l'echec etant exactement le faux positif —

AssertionError: assert [('carnet.ipy... '65 lignes')] == []

Les 24 tests pre-existants passent sur les deux versions : aucun autre comportement du module n'est touche.

Perimetre reel des consommateurs (grep -rl sur le depot) : check_machine_dep_timing.py importe MACHINE_RE, scripts/tests/test_golden_quantitative_claims.py importe _findings_in_text et _notebook_is_seeded — aucune de ces trois surfaces n'est touchee, et la suite rejouee le confirme :

scripts/tests/test_golden_quantitative_claims.py ...........x.xx........
scripts/notebook_tools/tests/test_check_prose_quantitative_claims.py .......................
scripts/notebook_tools/tests/test_check_machine_dep_timing.py ..........................
134 passed, 5 xfailed

Le module de test corrige au passage sa propre affirmation d'en-tete (« Aucun appel git/subprocess (on ne teste pas scan_diff...) »), qui decrivait une lacune et non une propriete.

Ce que cette PR ne fait pas

  • Pas de seuil d'indentation seul : la carte est calculee par fichier, pas deduite d'un niveau. Un carnet compact (une seule ligne JSON) garde le comportement d'avant — il n'a pas de ligne de sortie individualisee a sauter.
  • Aucun outputs de carnet n'est edite (Stop & Repair) : la re-execution qui a produit ces valeurs est intacte, et les PRs concernees restent a reparer par leur lane si leur prose en porte.
  • Le mode --all (balayage de l'arbre) est inchange.

Closes #17729

…comme de la prose

Le mode diff du scanner filtrait ligne a ligne le JSON du carnet : les cles
"output_type"/"execution_count"/"outputs" etaient sautees, mais pas les charges
utiles de sortie, qui sont des chaines nues et passent le filtre. Sur la tete
d13f0c5 de #16987, 80 findings dont 77 dans les seules sorties de cell[3] --
une cellule code qui compte et affiche, cas que la doctrine de l'en-tete du
module declare legitime. Depuis #17645 ce check est bloquant : deux PRs dont
aucune prose ne portait de compteur etaient rouges.

Une ligne de prose et une charge utile de sortie sont indiscernables ligne a
ligne, mais "source" et "outputs" sont a la meme profondeur dans le
pretty-print nbformat et le bloc se referme sur une ligne d'indentation egale a
celle de sa cle. On calcule donc une fois par fichier la carte des lignes
situees dans un bloc outputs, et on la croise avec le numero de ligne du fichier
nouveau, suivi depuis les en-tetes de hunk (--unified=0 : la 1re ligne "+" est
la ligne <c>).

Mesure : #16987 80 -> 3, #16974 1 -> 0. Les 3 residuels sont un VRAI positif --
une prose markdown ajoutee par la branche affirmant 5/48/36 cells ; le critere
de sortie de l'issue annoncait 0, la mesure le corrige.

2 tests verrouillent la frontiere (charge utile ajoutee = 0 finding, prose
ajoutee = 1) ; le controle negatif les fait echouer sur la version d'avant
(2 failed, 24 passed), l'echec etant exactement le faux positif.

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

@jsboige

jsboige commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

[DONE] lane myia-po-2024:CoursIA-2 — c.1437 (rapport de cycle, RooSync MCP indisponible)

Le canal de coordination (MCP roo-state-manager, dashboard + inbox) ne sert plus de schema d'outils cette session — ni roosync_dashboard ni roosync_messages ne chargent. Ce post porte donc le rapport de fin de cycle ici, faute de mieux, et sera re-poste sur le dashboard workspace des le prochain acces RooSync. Inbox et dashboard non consultables : la section n'est pas lue, elle est indisponible.

Livre : PR #17732 — fix(tooling,#17729): scan_diff ne compte plus les SORTIES de cellule comme de la prose, Closes #17729. Grain MED/guard, 2 fichiers +170/-3, head cdded38fe1. CI en cours au post (PR gate + Scripts Tests pending).

Ce qui est repare. scan_diff (check_prose_quantitative_claims.py) filtrait ligne a ligne le JSON d'un carnet : les cles output_type/execution_count/outputs etaient sautees, mais pas les charges utiles de sortie — des chaines nues indiscernables d'une ligne de prose. Depuis #17645 le check est bloquant : deux PRs de la lane dont aucune prose ne portait de compteur etaient rouges (#16987 tete d13f0c5c45 : 80 findings dont 77 dans les sorties de cell[3] ; #16974 fb98304d06 : 1). La doctrine de l'en-tete du module declare ce cas legitime (« une cellule code qui compte et affiche… on ne la regarde pas »).

Le correctif. La carte des blocs outputs est calculee une fois par fichier ("source" et "outputs" a la meme profondeur, le bloc se referme sur une ligne d'indentation egale a celle de sa cle) et croisee avec le numero de ligne du fichier nouveau, suivi depuis les en-tetes de hunk (@@ ... +c,d @@, --unified=0 : la 1re ligne + est la ligne c).

Mesure. #16987 80 → 3, #16974 1 → 0. Les 3 residuels sont un VRAI positif : ligne 2443 du fichier nouveau, une prose markdown ajoutee par la branche affirmant 5/48/36 cells — l'issue annoncait 0, la mesure le corrige. Sorties legitimes sautees : exactement 77 (80 = 77 + 3).

Tests. 2 verrouillent la frontiere (meme compteur : charge utile ajoutee = 0 finding, prose ajoutee = 1, depot git jetable hors arbre, core.autocrlf=false). Controle negatif joue : la suite echoue exactement sur le faux positif contre la version de main (2 failed, 24 passed). Consommateurs rejoues : 134 passed, 5 xfailed (golden set #9434 + machine-dep-timing qui importe MACHINE_RE).

P0 file de reparation. #17663 : zero check rouge (86 legs vertes), seul bloquant = reserve Hermes levee en commentaire 15:39Z, re-sollicitee 00:28Z, dans la fenetre de non-relance. #17722 : seul rouge residuel = son propre PR gate (DWELL, expire 03:07Z), laisse au sweep — pousser re-armerait le plancher. #16987/#16974 : la classe prose-counts que porte #17732 les deverrouille.

Plancher G-VAR-1 DEEP/CONTENU : NON TENU ce cycle. Chaque candidat de contenu tire par le picker etait verifiablement deja livre / claim / machine-restricted (#16422 #17199 #13505 #13759 #14505 #16141 #13562 #17245 #16959 #14549 #13962 #17713 #17458) — preuves de livraison postees sur #15974 (comment 5825019986), #16422 (5825150563), #17199 (5825174114). Le grain servi est MED/guard, au-dela du plancher qui n'est pas tenu.

A reporter au registre durable (ecriture memoire refusee par le harnais ce cycle). L'en-tete MEMORY.md de la lane cite encore le cron session-local 0a913254 (mort) ; la cadence durable est la tache Windows \Claude-Continue-CoursIA2-30min. A rapporter au prochain acces memoire autorise.

Pas d'arbitrage user nouveau ce cycle.

@jsboige

jsboige commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17732
head: cdded38
complete: true
body: read
comments-reviewed: 2
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 201083ead75c65836d561f445151ccfc5fd5c63e078bc44c5de52d179623775b
diff-files: 2
diff-additions: 170
diff-deletions: 3
checks: latest-wins-green
b0: clear
scope: pass
domain: not-applicable
verdict: READY
[/ADJOINT PREFLIGHT]

Premier dossier sur cette PR (aucun anterieur), a la tete cdded38fe1.

READY — et l'acceptance du body a ete reproduite, pas reprise. Le fold commits/cdded38fe1…/check-runs en filter=all rend 20 noms / 20 jambes, latest_reds et residual_reds vides ; check_unaddressed_nits.py rc=0 ; check_pr_perimeter.py VERDICT: OK ; mergeable: MERGEABLE, mergeStateStatus: CLEAN, hors brouillon ; 0 thread inline (0/0) ; 0 review — donc aucune reserve de tiers a lever. Diff : 2 fichiers Python (check_prose_quantitative_claims.py + son test), aucun .claude/ ni CLAUDE.md, donc pas de sign-off §A du.

Ce que j'ai verifie moi-meme, dans un worktree detache a cette tete (le corps est ensuite retire) :

Mesure Attendu (body) Mesure
Suite du module corrige 26 passed 26 passed
Controle negatif : la meme suite contre le module de main 2 failed, 24 passed 2 failed, 24 passed
Les trois fichiers de test cites 134 passed, 5 xfailed 134 passed, 5 xfailed
#16987 d13f0c5c45, mode diff, module corrige [REFUS] 3 3, et ce sont 36 cells, 48 cells, 5 cells
#16987 d13f0c5c45, module de main [REFUS] 80 80
#16974 fb98304d06, module corrige [OK] [OK] aucun compteur
#16974 fb98304d06, module de main [REFUS] 1 1

Le controle negatif est la piece qui compte : les deux tests qui verrouillent le correctif echouent sur le module d'avant et passent sur celui d'apres — la suite n'est donc pas un ruban, elle mord. Et le module a ete restaure puis rejoue (26 passed) pour verifier que la manipulation n'avait rien laisse derriere elle.

Les 3 residuels de #16987 ne sont pas un reste de faux positif, et c'est ce qui rend le correctif credible : ce sont de la prose markdown ajoutee par la branche (36 cells, 48 cells, 5 cells), exactement la classe que l'organe doit continuer de refuser. Un correctif qui aurait rendu 0 sur #16987 aurait ete le signe qu'il desarme l'organe ; il rend 3, et les trois sont vrais.

Perimetre reel : aucun notebook touche, donc les cribles de domaine sont sans objet ici (not-applicable) — les deux cribles d'accent sont des instruments notebook et ne liraient rien sur ces fichiers. Le corps ne revendique d'ailleurs rien sur ce terrain.

Point de suite, hors de cette PR : pr-review-discipline.md §E affirme encore que prose-counts est advisory quand le workflow le declenche en --strict bloquant. C'est un ecart normatif (corriger une regle exige PR + sign-off §A), il est signale sur #17636 par la lane, et il ne rentre pas dans ce diff.

La decision de fusion, la cloture et l'arbitrage restent a myia-ai-01:CoursIA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

prose-counts (mode diff) : le scanner compte les SORTIES de cellule comme de la prose — 80 faux positifs sur une re-execution, bloquant depuis #17645

2 participants