Repository navigation
fix(nb-tools,#16110): source-collapse ratchet — second mechanism, structural fold - #16112
Conversation
…uctural fold The existing organ (#15901) measures source VOLUME. A cell whose source folds entirely into a comment is invisible to it by construction: on the founding case (PR #16097, Lean-18 cell 40cb37d5) the head GROWS 1132 -> 1728 chars because the same write that stripped the newlines appended a 639-char recovery note, so the magnitude gate stops before any floor. The BLOCKING notebook-cell-source-parses guard is blind too -- a fully commented cell parses clean -- which is why it stayed green on a cell whose code had disappeared. Adds two structural signals to the SAME check-run, no new fast-lane wiring: * `emptied` matched cell whose statement count went from > 0 to 0. * `orphan-output` non-empty outputs with 0 statements and no IPython magic (base-free by construction -- the issue's 3rd criterion). The existing exemptions speak about the base->head RELATION, so they arbitrate the comparative signal only; `orphan-output` is intra-cell and stays true whatever happens to the code elsewhere. Both exemption fractions measure 0.00 on the founding case, so nothing was suppressed. `_scan_line` / `_strip_ipython_magics` / `_is_python_kernel` are imported from check_cell_source_parses rather than reimplemented, so the organs cannot disagree about the same cell. Criterion 1 of the issue (unterminated-item count) is REFUTED by measurement, not implemented: per-character serialization already exists on main (GenAI/Texte/21_LoRA_FineTuning.ipynb cell 69b296cb -> 802 unterminated items, 10 statements, real output, healthy). Histogram over the 11970 code cells of main's 953 Python notebooks: {0: 11970, 1: 1, 802: 1}. The signal is withdrawn rather than shipped with a threshold; the folds it targeted are covered twice without it (code-first fold -> the blocking syntax guard; comment-first fold -> `emptied`). Calibration: 0 structural findings on main's full Python corpus; 0 structural findings on the 18 notebooks changed by 12 merged PRs (#16080, #16071, #16069, #16067, #16041, #16039, #16027, #16024, #16021, #16020, #16013, #16012). A first sweep without the no-magic guard flagged 6 cells, all `# comment` + `!python`/`%pip` -- the magic IS the producer, so the guard is measured necessity, not caution. Evidence: 30 tests green in the file, 89 across the sibling organ files; `--self-test` OK with BOTH founding-case replays firing (volume #15901 and structure #16110); live end-to-end run at #16097's head reports the exact measured finding with RC=1. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Grain tag obligatoire (#10045, bloquant).
Pour passer ce gate, le body doit porter en tete une ligne de la forme : Le |
|
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 |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: LGTM
[Hermes] — #16112 second mécanisme source-collapse structurel, review sur head 9e7b53fc, exécution firsthand.
Vérifications faites :
- Self-test exécuté firsthand (fichiers fetchés au head SHA) :
SELF-TEST OK: witnesses fired, benign churn silent, exemptions hold, both founding cases fire (volume #15901, structure #16110)— exit 0. - Suite pytest : 30/30 passés (13 neufs + 17 existants).
- Le discriminant structurel est réel :
_python_statements(l.295-314) comptelen(ast.parse(stripped).body)— une source réduite à un commentaire fait 0 statement là où le ratchet volume la voit « longue » (1728 car. > 1132 base). C'est bien la classe #16110 invisible au mécanisme 1 par construction. - Périmètre fidèle au body : 4 fichiers annoncés = 4 fichiers dans le diff ; l'organe étendu reste le même check-run (famille
check_source_collapse), pas de nouvelle voie rapide câblée. - Sécurité : grep credentials sur le diff = 0 match.
Le tableau base/head de l'issue (44→12 items, 10→0 statements, execution_count 7→None, +639 car. de note de récupération) est cohérent avec le mécanisme introduit — un cas qui volume-passe et structure-fail.
(contrainte #15511 : COMMENT-only sur CoursIA)
Path-collision (organ #13359/#13615)Cette PR #16112 (
Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur |
Grain: MED/ci -- lane myia-po-2023:CoursIA
Sujet
#16110 : une cellule code dont la source s'effondre en un commentaire passe tous les organes au vert. Le ratchet de source existant (
check_source_collapse.py, #15901) mesure le volume ; ce défaut-là est structurel — il lui est invisible par construction. Cette PR ajoute le second mécanisme à l'organe existant (même famille, même check-run, aucune nouvelle voie rapide à câbler).Périmètre effectif : 4 fichiers —
scripts/notebook_tools/check_source_collapse.py(critères structurels +--self-test+ impression),scripts/notebook_tools/tests/test_check_source_collapse.py(13 tests neufs, 30 au total),.claude/rules/pr-review-discipline.md(point 8 : ce qu'exige un findingSTRUCTURE),scripts/ci/fast_lane_registry.py(l'en-tête TRANCHE11 dit désormais les deux mécanismes).Le défaut, mesuré firsthand (pas repris du body de l'issue)
Même cellule,
Lean-18-Sendov-Complex-Analysis.ipynbcellule40cb37d5,origin/maincontre la tête de #16097 (1209b5357) :sourcelen(ast.parse(source).body)execution_countNoneLe head est long : le même geste qui a retiré les
\na ajouté une note de récupération de 639 caractères. Deux instruments restent donc verts, et aucun n'est en défaut :h_chars >= b_chars→ le gate s'arrête avant tout plancher. Vérifié :analyze()rend zéro finding sur cette cellule.notebook-cell-source-parses(Aucun garde ne parse la source des cellules : une cellule non compilable portant une sortie traverse les 60+ checks #13326) est resté vert sur une cellule dont le code a disparu — et l'issue dit elle-même que « la syntaxe n'est pas le bon instrument ».Ce qui est implémenté
Le discriminant est le nombre d'instructions (magics IPython retirés, même machine à états que le garde bloquant — réutilisée, pas réécrite) :
emptied— cellule appariée dont la source passait de> 0instruction à0. Basé sur le contenu : peu importe comment les\nont disparu.orphan-output— la cellule porte desoutputsnon vides et0instruction : un résultat qu'aucune instruction ne peut avoir produit. Sans base par construction (ni baseline ni diff, seulement la cellule) — le 3ᵉ critère de l'issue.Les exemptions existantes (contenu déplacé, purge de diagnostic) arbitrent les signaux comparatifs : elles énoncent « rien ne s'est effondré ici », ce qui est une affirmation sur la relation base→head. Elles ne blanchissent pas
orphan-output, dont l'affirmation est intra-cellule et reste vraie quoi qu'il arrive au code (le contenu déplacé ailleurs laisse quand même une sortie orpheline au-dessus d'une cellule vidée). Sur le cas fondateur, les deux fractions d'exemption mesurent 0.00 : elles n'auraient rien supprimé.Ce qui n'est PAS implémenté, et pourquoi (critère 1 de l'issue : réfuté par mesure)
Le critère 1 (« le nombre d'items de
sourcesans\nfinal augmente ») mesure la granularité de sérialisation, pas une corruption. Témoin surmain:GenAI/Texte/21_LoRA_FineTuning.ipynbcellule69b296cbest sérialisée caractère par caractère (['#', ' ', 'P', …], 820 items) → 802 items non terminés, et pourtantast.parserend 10 instructions et sa sortie est réelle : la cellule est saine.Histogramme des items non terminés sur les 11 970 cellules de code des 953 notebooks Python de
main:{0: 11970, 1: 1, 802: 1}.Un détecteur dont le déclenchement dépend de l'outil qui a sérialisé la cellule signalerait des re-sérialisations légitimes : le signal est retiré plutôt que livré avec un seuil. Les cas de repli qu'il visait sont déjà couverts deux fois : un repli dont la première ligne est du code perd sa syntaxe (garde BLOQUANT ci-dessus) ; un repli dont la première ligne est un commentaire est pris ici par
emptied.Deux pièges mesurés avant d'écrire le prédicat
# commentaire+!python …/%pip install …. Leur sortie a un producteur (le magic) ;astn'en voit aucun parce que le stripper a retiré la ligne. Le prédicat exige donc aucun magic (même règle de ligne logique que le stripper). Avec ce garde, le balayage demainrend ZÉRO cellule : le critère n'a aucune instance préexistante dont il faudrait être conservateur.mainn'en porte aucun.orphan-outputn'est donc délibérément pas restreint aux cellules éditées : là où l'affirmation est intra-cellule, la baseline n'ajoute rien.Calibration (faux positifs)
main.magnitudepréexistant, inchangé par cette PR.Preuves
test_check_source_collapse.py30 verts (13 neufs : cas fondateur,emptiedsans sortie,orphan-outputsans baseline, magic non-orphelin, magic inchangé silencieux, granularité par caractère silencieuse, exemptionmovedqui ne blanchit pas l'orphelin, notebook ajouté jamais jugé, noyau non-Python hors passe structurelle, sémantique de_python_statements, règle de ligne logique des magics,_format_deltasigné).--self-test:SELF-TEST OK— et les deux replays du cas fondateur tirent : volume Ratchets notebook : aucun organe ne mesure la substance de la SOURCE — 3116 caracteres et un verificateur entier supprimes sous 30 checks verts (#15862) #15901 (c989_independent_v2, 8425 → 5309,magnitude) et structure Notebook: une cellule code dont la source s'effondre en un commentaire passe tous les organes au vert (source detruite, sortie conservee) #16110 (40cb37d5,structure,['orphan-output','emptied'], instructions 10 → 0, perte −596 = croissance).python scripts/notebook_tools/check_source_collapse.py origin/main→1 changed notebooks | 1 flagged (advisory),STRUCTURE: cell 40cb37d5 signals orphan-output,emptied -- statements 10 -> 0, 1132 -> 1728 chars, RC=1. Le chemin--jsonporte les mêmes champs (base_body/head_body/signals/loss).emptiedici ; sortie sans producteur →orphan-outputici ; perte de volume → ratchet Ratchets notebook : aucun organe ne mesure la substance de la SOURCE — 3116 caracteres et un verificateur entier supprimes sous 30 checks verts (#15862) #15901.SOTA / portée
Aucun notebook touché, aucun outil dégradé : une PR d'organe CI, advisory par design (
blocking=Falseinchangé dans la voie rapide). Le jugement reste au reviewer ; l'organe rend la perte visible.Closes #16110
🤖 Generated with Claude Code