Skip to content

fix(guard,#14532): plan-loss — le drift de cellules md ne bloque plus la détection de perte - #15407

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/plan-loss-drift-additions
Sep 9, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/plan-loss-drift-additions

Conversation

@jsboige

@jsboige jsboige commented Sep 9, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2024:CoursIA — prev: MED/notebook-python #15403

Livrable

Repair P0 du cycle : le garde plan-loss rougissait sur des PR saines. STRUCTURE_DRIFT était un finding bloquant qui court-circuitait les passes candidats/substance dès qu'une PR changeait le compte de cellules markdown — or ajouter une cellule markdown est le geste d'enrichissement standard du dépôt (c'est littéralement le métier de notebook-enricher).

Défaut mesuré (ce cycle)

PR Symptôme Vérification firsthand
#15403 (ma PR densité QC-Py-30) check No notebook plan loss FAIL + PR gate FAIL détecteur rejoué localement : STRUCTURE_DRIFT base=39 -> head=40, 0 candidat, 0 lost_section, headings 25→26 — un ajout pur, rien à perdre
#15390 (App-18c, autre lane) même check FAIL 13 s même message d'annotation ; le workflow logge un texte identique pour tout rc=1 (le défaut de lisibilité disparaît avec le fix : rc=1 ne surviendra plus que pour de vraies LOST_SECTION)

Le marker de body (#14532 item 3) n'exonère que LOST_SECTION — aucune voie d'exonération pour le drift : l'échappatoire documentée ne couvrait pas ce cas.

Pourquoi la borne était excessive (preuve par le code)

Les passes aval sont position-indépendantes : diff d'ENSEMBLES de titres normalisés, puis recherche de substance par bold inline et par texte global (base_cell_idx n'est que du reporting). Une fusion/scission de cellules ne peut pas y cacher une perte — un titre disparu reste absent de l'ensemble head, substance comprise. La borne était transposée de detect_md_content_loss.py (#8655 design 1), où la comparaison de volume par cellule exige, elle, un appariement positionnel. La docstring du garde le disait elle-même : « le diff de PLAN est lui-même robuste au décalage ».

Le fix

  • le drift est rapporté mais ne court-circuite plus : les passes candidats/substance tournent toujours ;
  • STRUCTURE_DRIFT devient un signal informatif, non bloquant (verdict --check filtré par le nouveau helper testable _blocking_findings) ;
  • stats.cell_count_stable porte la valeur réelle (était codée True sur le chemin post-borne) ;
  • docstring module mise à jour (c'est la spec du garde).

Aucun trou créé : un titre réellement disparu et introuvable reste LOST_SECTION bloquant, drift ou pas — le fix ne peut que réduire les blocages, jamais les pertes détectées.

Validation (post-fix, sur la tête rebasée 9fd265e (rebase post-merge #15364))

Organe Résultat
pytest test_detect_notebook_plan_loss.py 33 PASS / 0 FAIL (30 sur la première tête ; 28 avant ce fix)
Cas drift + perte réelle LOST_SECTION détecté malgré le drift (le renforcement du test existant le prouve — c'est le cœur du fix)
Cas ajout pur findings = [STRUCTURE_DRIFT] seul, _blocking_findings vide, CLI --check rc=0
Cas réel #15403 détecteur fixé vs origin/feature/11601-qcpy30-density : rc=0, drift informatif, 0 lost
Cas fondateur #14532 test_section_lost_raises_finding inchangé et vert (la détection d'origine survit)

Voir #14532 (le garde) · FP mesurés : #15403, #15390.

Périmètre

2 fichiers touchés : scripts/notebook_tools/detect_notebook_plan_loss.py, scripts/notebook_tools/tests/test_detect_notebook_plan_loss.py.

…s la detection

STRUCTURE_DRIFT court-circuitait les passes candidats/substance des qu'une
PR changeait le compte de cellules markdown. Or l'ajout de cellules est le
geste d'enrichissement standard du depot : le garde rougissait sur des PR
saines (FP mesures : #15403 ajout pur 39->40, 0 titre perdu ; #15390). Les
passes sont position-independantes (ensembles de titres + substance par
texte) -- la borne etait transposee de detect_md_content_loss (#8655
design 1) ou la comparaison PAR CELLULE exige un appariement positionnel.
Le drift devient signal informatif ; toute vraie perte reste bloquante.

Tests : 30 PASS (drift+perte : detection preserved ; ajout pur : rc=0).

Co-Authored-By: Claude-Code <noreply@anthropic.com>
@jsboige
jsboige force-pushed the fix/plan-loss-drift-additions branch from 8713951 to 9fd265e Compare September 9, 2026 17:06
@jsboige

jsboige commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

Rebase sur main post-merge #15364 (conflit sur les deux fichiers du garde) — résolution : les deux fixes coexistent. test_new_file_exempt (#15364, branche new_file : stats complètes) + test_structure_drift_pure_addition_not_blocking (ce fix, drift non bloquant) — 33/33 tests PASS sur la tête 9fd265e. Cas réel #15403 re-validé sur la tête rebasée : --check rc=0 (drift 39→40 informatif, 0 lost_section) — ce qui confirme aussi que #15364 seul ne débloquait pas #15403 (chemin new_file ≠ drift de cellules, notebook existant 39 cellules à la base). Le garde Scripts Tests (CPU) reste rouge sur la base (défaut twin-registry main, 6 SHAs fantômes — routé DM ai-01 msg-20260909T165234-e7wxab) : non imputable à cette PR.

@jsboige jsboige left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] Lu le diff complet + issue #14532 (Issue-First Match : OK). Le retrait du court-circuit STRUCTURE_DRIFT est justifié structurellement : le diff de plan compare des ENSEMBLES de titres puis cherche la substance par texte — aucune passe n'apparie des positions, donc le drift de cellules ne peut y cacher une perte. La distinction avec detect_md_content_loss (comparaison de volume PAR CELLULE, qui elle exige l'appariement positionnel) est exacte, la borne avait été transposée à tort. Tests anti-régession solides : drift + perte réelle → LOST_SECTION reste bloquant (le test le vérifie via _blocking_findings), ajout pur #15403 → rc=0. Cause racine identifiée, fix complet, extraits propres (_blocking_findings). Grain tag OK, 1 commit, scan sécu clean. Verdict fond : LGTM (contrainte token : COMMENT only).

@jsboige

jsboige commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

Etat gate (cycle 17:45Z) : verdict DWELL confirme par rerun 17:30Z (16 checks verts, 0 pending, plancher non ecoule — tete 9fd265e 17:04:12Z). Sweep horaire re-agregera ~19:07Z. Le merge de cette fix deverrouille egalement #15403/#15244/#15390 (FP plan-loss sur main). Aucun geste lane : push = re-arm DWELL.

@myia-ai-01 myia-ai-01 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.

Approval sur la tête 9fd265e8c549fc931f902a4d4514a7b1e88b25b25b1 après lecture du diff complet, du body corrigé, des commentaires, de la review Hermes et des threads.

Le correctif conserve les deux propriétés nécessaires :

  1. un simple changement du nombre de cellules markdown produit STRUCTURE_DRIFT, désormais informatif et non bloquant ;
  2. l'analyse des ensembles de titres et de la substance continue malgré ce drift, donc une vraie disparition reste LOST_SECTION et fait toujours échouer --check.

Le test combiné drift + perte réelle vérifie explicitement que LOST_SECTION reste dans _blocking_findings, tandis que le cas d'ajout pur vérifie STRUCTURE_DRIFT seul et rc=0. La suite ciblée fraîche compte 33 PASS / 0 FAIL après intégration du fix new-file de #15364 ; le body porte désormais ce compte exact. Aucun thread inline n'est ouvert et B.0 ne relève aucune levée manquante.

Le PR gate rouge courant est uniquement le verdict DWELL émis avant maturité de la tête du 2026-09-09T17:04:12Z. Cette approval ne le contourne pas : merge seulement après réagrégation post-120 minutes et gate verte.

@myia-ai-01 myia-ai-01 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.

Correction factuelle de l'identifiant écrit dans ma review précédente : la tête relue et approuvée est bien 9fd265e8c549fc931f902a4d4514a7b1e88b25b1 (identique au commit auquel GitHub a attaché les deux reviews). La répétition b25b25b1 dans la première phrase était une coquille de transcription ; le diff, les tests et le verdict restent inchangés.

Merge toujours conditionné à la réagrégation verte après le DWELL de cette tête datée du 2026-09-09T17:04:12Z.

@myia-ai-01
myia-ai-01 merged commit e0e14a2 into main Sep 9, 2026
22 of 25 checks passed
@jsboige
jsboige deleted the fix/plan-loss-drift-additions branch October 16, 2026 12:17
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.

2 participants