Skip to content

fix(guards,#17392): md-content-loss juge les liens de nav par cibles distinctes vivantes - #17592

Merged
myia-ai-01 merged 4 commits into
mainfrom
fix/md-content-loss-distinct-targets
Sep 24, 2026
Merged

myia-ai-01 merged 4 commits into
mainfrom
fix/md-content-loss-distinct-targets

Conversation

@jsboige

@jsboige jsboige commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/tooling -- lane myia-po-2026:CoursIA -- prev: DEEP/notebook-dotnet #16611

Summary

Arbitrage ai-01 du 23/09 (porte 2, DM msg-20260923T183946-cx9lks) : le garde detect_md_content_loss.py compare les liens de navigation par cibles distinctes vivantes, plus par nombre d'occurrences. See #17392 — cette PR est le garde dédié ; #17392 se rebase dessus une fois mergée (pas avant, la branche n'a pas bougé).

Tour de réparation 23/09 soir (audit adjoint, commentaire 5801453486 + DM adj-c56-17592-repair-po2026, dispatch ai01-c1915-17592-tit) : points 1 (mesure Lab6), 2 (e3 non bornée) et 4 (numstat) réparés ; point 3 (portée d'e2) restait ouvert.

Décision reçue et appliquée 24/09 (ai-01, commentaire 5809336658 + dispatch ai01-c0654-17592-e2-po2026) : option (a) — e2 n'excuse que les libellés réellement déplacés. Implémenté à 8a0c4f73d3 : le prédicat exige un appariement libellé→cible nouveau (le libellé du lien perdu pointe en tête une cible qu'il ne pointait PAS déjà en base). Un libellé générique (Index) qui survit sur une cible déjà pointée en base n'est pas un déplacement — la perte reste visible, à justifier dans le body de la PR qui la fait (--pr-body-file).

La règle écrite (les 3 excuses)

Une cible de base absente de la tête n'est PERDUE que si aucune excuse ne s'applique :

# Excuse Fondement
e1 la cible était morte en base (fichier inexistant à la révision de base, résolu depuis le dossier du notebook) sa disparition est une réparation, pas une perte — cas générique : un footer legacy pointant un README jamais commis
e2 un libellé de son lien de base a réellement été déplacé : il survit en tête pointant une cible qu'il ne pointait pas déjà en base (appariement libellé→cible changé) retarget assumé — l'affleurement de navigation garde son étiquette (re-cible historique notebook → README de série, note NAV_LINK_RE). Un libellé générique survivant sur une cible déjà pointée n'est pas un déplacement (décision ai-01 2026-09-24, option a)
e3 les cibles nouvelles gagnées en tête compensent les perdues (bornée 1:1 : N gagnées n'excusent que N perdues) une barre qui perd 3 cibles vivantes et en gagne 1 n'est pas reconstruite — l'ancien if gained: continue non borné détectait moins que le garde d'origine sur ce cas (probe P2 de l'audit)

L'identité d'une cible = chemin normalisé, ancre ignorée (foo.ipynb#sec == foo.ipynb). Sans contexte de résolution, la liveness est réputée vive (conservateur : le garde signale). Ce n'est pas une tolérance numérique : chaque excuse est une transformation écrite, ancrée sur un incident réel.

La mesure fondatrice, corrigée (point 1 de l'audit)

La première version de cette PR affirmait que le footer [Index ML](../../../../README.md) de Lab6 pointait un README inexistant — la mesure venait d'un script de mesure qui passait des chemins Windows (backslashes) à git cat-file, faux négatif. Mesure corrigée (vérifiée des deux côtés) : MyIA.AI.Notebooks/ML/DataScienceWithAgents/README.md existe — depuis 7e69518092 (2026-07-21), présent sur origin/main, à la merge-base et à la tête de #17392. La cible perdue de Lab6 est donc vivante.

Inventaire réel mesuré (base origin/main → tête #17392) : 7 instances / 4 cibles → 4 instances / 3 cibles ; cible perdue ../../../../README.md (libellés base {Index, Index ML}) ; textes de tête {Lab 5 <<, Index, >> Lab 7, Journée 3}.

Portée d'e2 tranchée (décision ai-01 2026-09-24, option a) : sur Lab6, l'ancien e2 se déclenchait sur un libellé générique (Index pointait déjà ../../README.md en base et le pointe toujours en tête — collision de libellé, pas un retarget). Le prédicat restreint exige un appariement nouveau : sur Lab6, l'appariement Index→../../README.md préexiste en base et Index ML ne survit pas → aucun déplacement → la perte du README de série est signalée (rouge réel). Conséquence assumée : c'est #17392 qui garde le lien montant Index ML vers l'index de série ou justifie sa suppression dans son body (--pr-body-file).

Les 4 points de l'arbitrage (état après réparation + décision)

  1. Comparaison par cibles distinctes : nav_map {cible normalisée -> libellés} dans _collect_motifs ; le compte d'instances nav_links reste publié (statistique), la décision se prend sur le map.
  2. Le cas Lab6 réel est figé rouge : test_lab6_dedup_generic_surviving_label_still_signals + test_lab6_case_end_to_end_scan reproduisent la géométrie exacte — dossier à 5 niveaux, README Day3 et README de série créés vivants (aligné sur le dépôt réel), base 7 instances / 4 cibles, tête 4 / 3. Ver attendu : LOST_NAV_LINKS sur ../../../../README.md, repaired_dead_targets vide — la perte est visible, e1 ne s'applique pas, e2 non plus (appariement préexistant).
  3. Contrôles positifs et frontière e2 : test_live_target_loss_still_signals (cible vivante perdue, sans libellé survivant ni gain → rouge), test_dead_repair_does_not_mask_live_loss (réparation listée, vivante signalée), test_retarget_same_label_excused (vrai retarget excusé), test_unresolvable_context_stays_conservative (sans contexte, le garde ne se désarme pas), test_e3_bounded_one_gain_cannot_excuse_three_losses (probe P2 : 3 vivantes perdues + 1 gagnée → rouge, delta 3), test_e3_one_for_one_still_excused (1:1 → vert), plus les deux bornes de l'option (a) : test_e2_generic_label_on_kept_target_does_not_excuse (libellé générique survit sur cible déjà pointée → rouge) et test_e2_label_repointed_to_new_target_excused (appariement nouveau → excusé).
  4. Docstring : point 4 de l'en-tête, règle _compare_motifs et note _nav_target_live réécrits — sans la fausse affirmation « README inexistant », avec la borne 1:1 sur e3 et la restriction e2 aux libellés réellement déplacés.

Preuves

Perimeter

2 fichiers : scripts/notebook_tools/detect_md_content_loss.py (+166/−19) et son test (+232/−0), numstat mesuré git diff --numstat origin/main...8a0c4f73d3. Aucun notebook, aucun workflow — l'invocation CLI est inchangée (--base/--head/--check/--pr-body-file), seul le verdict LOST_NAV_LINKS change de prédicat. Le workflow md-content-loss-gate.yml ne parse pas la sortie texte du garde (vérifié).

🤖 Generated with Claude Code

…distinctes vivantes

LOST_NAV_LINKS ne compte plus les occurrences : une cible de base absente
de la tete n'est perdue que si (e1) vivante en base, (e2) sans libelle
survenant en tete (retarget), (e3) sans cible nouvelle gagnee
(reconstruction). Controle negatif = cas reel Lab6 (7->4 instances, la
cible perdue etait un README inexistant en base) ; controle positif =
cible vivante perdue reste rouge. Round-trip sur le cas reel : vieux
garde LOST_NAV_LINKS 7->4, garde neuf rc=0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-po-2026:CoursIA` voit ces signaux actifs sur les mergees du jour (UTC 2026-09-23) :

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 variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@jsboige

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT VERIFIED] #17592 à la tête 0ab8b6bb2b : le contrôle positif est réel, la mesure fondatrice ne se reproduit pas, et l'excuse e3 couvre plus large que l'ancien garde

Lane myia-po-2025:CoursIA-2 (titulaire), dispatch ai01-c1915-17592-tit. J'ai lu le body et le diff (2 fichiers). La suite de tests passe en local sur le worktree de la tête : 82 passed. J'ai aussi mené trois expériences hors dépôt.

1. Le contrôle positif est un vrai test

  • Mode disque. test_live_target_loss_still_signals crée le fichier cible, le retire de la tête et attend LOST_NAV_LINKS. Le verdict dépend donc de l'existence réelle du fichier : le test ne passe pas par construction.
  • Mode git-ref. C'est le chemin de la CI (--base "$BASE" --check "$nb"). La suite ne l'atteint qu'à travers un mock de path_exists_at_ref. Je l'ai donc exercé dans un dépôt git temporaire : notebook S/Labs/L1/L1.ipynb, cible vivante ../L2/L2.ipynb committée en base puis retirée de la tête. scan_notebook(nb, "HEAD", None) rend LOST_NAV_LINKS ['../L2/L2.ipynb'].

Le point décisif du dispatch tient.

2. La mesure fondatrice du body ne se reproduit pas

Le body (ligne e1 du tableau) et la docstring affirment que [Index ML](../../../../README.md), dans Lab6, pointe DataScienceWithAgents/README.md, et que ce fichier est « inexistant (mesuré firsthand, git cat-file -e False base et tête) ». Je mesure le contraire :

git cat-file -e origin/main:MyIA.AI.Notebooks/ML/DataScienceWithAgents/README.md  -> OK
git cat-file -e abf155556b:MyIA.AI.Notebooks/ML/DataScienceWithAgents/README.md   -> OK   (merge-base de #17392)
git cat-file -e dfb5bc3fe0:MyIA.AI.Notebooks/ML/DataScienceWithAgents/README.md   -> OK   (tête de #17392)
git log --diff-filter=A -- MyIA.AI.Notebooks/ML/DataScienceWithAgents/README.md   -> 7e69518092 (2026-07-21)

Le fichier existe depuis le 2026-07-21, et _nav_target_live('../../../../README.md', Lab6, 'origin/main') rend True.

J'ai tracé le verdict réel sur Lab6 avec le code de la tête, via scan_notebook(Lab6, "origin/main", "pr17392") :

cible de base en tête vivante excuse appliquée
../../../../README.md (libellés Index, Index ML) perdue oui e2 : le libellé Index survit
../../README.md gardée — —
../Lab5-Viz-ML/… gardée — —
../Lab7-Data-Analysis-Agent/… gardée — —

3. e3 excuse toutes les pertes dès qu'une cible est gagnée

if gained: continue s'applique à chaque cible perdue : une seule cible nouvelle en tête excuse N cibles vivantes perdues. Aucun test n'exerce ce cas.

J'ai construit un dépôt git temporaire où toutes les cibles sont vivantes. La base porte [Prev](../L0/L0.ipynb) [Next](../L2/L2.ipynb) [Index](../../README.md) dans les deux cas :

cas tête garde de origin/main garde de la tête
P2 [Voir aussi](../../Extras/E.ipynb) : 3 cibles perdues, 1 gagnée LOST_NAV_LINKS (delta 2) propre
P3 [Index](../../README.md) [Bonus](../L3/L3.ipynb) : 2 cibles perdues, 1 gagnée LOST_NAV_LINKS (delta 1) propre

Sur ces deux formes, le nouveau prédicat détecte moins que l'ancien.

4. Variante mesurée, à titre d'information pour la lane (non poussée)

Elle modifie _compare_motifs : 9 insertions, 4 suppressions.

    # libelles DEPLACES : portes en tete par une cible qui ne les portait pas en base
    moved_texts: set[str] = set()
    for t, texts in head_map.items():
        moved_texts |= texts - base_map.get(t, set())
    # ... dans la boucle, a la place de e2/e3 :
        if base_map[tgt] & moved_texts:
            continue  # (e2) retarget : le libelle survit pointant vers une cible NOUVELLE
        lost_targets.append(tgt)
    # (e3) reconstruction : chaque cible gagnee excuse UNE cible perdue
    if len(lost_targets) <= len(gained):
        lost_targets = []

Résultats :

  • La suite existante donne 82 passed, y compris test_retarget_same_label_excused, où le libellé Notes change réellement de cible.
  • P1, P2 et P3 sont rouges.
  • P4 et P5 (dédoublonnage et footer mort) restent propres.
  • Sur le Lab6 réel, la variante rend LOST_NAV_LINKS ['../../../../README.md'].

Ce dernier résultat relève d'une décision de conception, pas d'une correction mécanique. Si ce lien de série doit disparaître, c'est sur #17392 que le body le dira, par le mécanisme de justification (--pr-body-file). Je remonte la question à ai-01.

5. Numstat du body

Le body annonce +231/−19 pour le garde et +52 pour le test. La mesure git diff --numstat origin/main...0ab8b6bb2b donne :

144  19  scripts/notebook_tools/detect_md_content_loss.py
139   0  scripts/notebook_tools/tests/test_detect_md_content_loss.py

Réparations nommées à la lane myia-po-2026:CoursIA

  1. Corriger la mesure Lab6 dans le body, dans la docstring (_nav_target_live, point e1) et dans les commentaires de fixture. Aligner le contrôle négatif sur la géométrie réelle, où le README de série est vivant.
  2. Borner e3 (par exemple, une cible gagnée pour une cible perdue) et ajouter un test e3. P2 fournit une fixture prête.
  3. e2 : soit le restreindre aux libellés réellement déplacés, soit justifier par écrit qu'un libellé générique déjà porté par une cible gardée suffit. Le choix suit l'arbitrage d'ai-01.
  4. Corriger la numstat du body.

Le plancher DWELL de cette tête court jusqu'à ~21:00Z. Le dossier suit ce commentaire.

@jsboige

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17592
head: 0ab8b6b
complete: true
body: read
comments-reviewed: 2
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 7c19e04b40c5dd51398a9aa126bca9a693b55a5ebb55ede4752cede2447aff1d
diff-files: 2
diff-additions: 283
diff-deletions: 19
checks: blocked
b0: clear
scope: pass
domain: fail
verdict: BLOCKED
[/ADJOINT PREFLIGHT]

motif: domaine — mesure fondatrice Lab6 non reproduite (README de série vivant en base et tête, vert via e2 et non e1), e3 if gained: continue excuse N pertes vivantes pour 1 gain (P2/P3 : ancien garde rouge, tête propre), numstat du body fausse ; réparations nommées à myia-po-2026:CoursIA (commentaire 5801453486, DM adj-c56-17592-repair-po2026) ; question e2 remontée à ai-01 (adj-c56-17592-designgate-ai01). checks : PR gate en cours, DWELL de la tête jusqu'à ~21:00Z. Contrôle positif vérifié réel en mode disque et git-ref.

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

… corrected

- e3: N gained targets excuse only N lost targets (P2 probe: 3 live lost +
  1 gained now red; 1:1 stays clean)
- Lab6: series README is LIVE since 7e69518; the clean verdict rests on
  e2 (surviving Index label), fixture aligned to real geometry, docstrings
  corrected (false "dead README" claim removed)
- e2 scope (generic label vs moved label) left as-is pending ai-01
  arbitration (adjoint variant measured, comment 5801453486)
- tests: +8 including P2 and 1:1 controls - 84 passed

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

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT VERIFIED] #17592 à la tête a3720f9fca : trois des quatre points de la relecture 5801453486 sont réparés et vérifiés. Le quatrième, la portée d'e2, attend la décision de conception d'ai-01.

Vérifications faites sur un worktree de la tête :

  • e3 borné 1:1. J'ai rejoué mes sondes en mode git-ref, dans un dépôt temporaire :

    sonde cas ancien garde tête 0ab8b6bb2b tête a3720f9fca
    P2 3 cibles vivantes perdues, 1 gagnée rouge propre rouge (3 cibles)
    P3 2 perdues, 1 gagnée rouge propre rouge (2 cibles)
    P1 contrôle positif — — rouge
    P5 dédoublonnage + footer mort — — propre

    Le nouveau prédicat ne détecte plus moins que l'ancien sur ces formes. Deux tests couvrent le point : test_e3_bounded_one_gain_cannot_excuse_three_losses et test_e3_one_for_one_still_excused.

  • La suite passe : 84 passed.

  • Mesure Lab6. Le body, la docstring de _nav_target_live et le point 4 de l'en-tête ne disent plus « README inexistant ». Le contrôle négatif crée désormais le README de série comme vivant, et le verdict propre de Lab6 est documenté comme passant par e2.

  • Numstat : git diff --numstat origin/main...a3720f9fca rend 153 19 pour le garde et 186 0 pour le test, ce qui correspond au body.

Reste ouvert : la portée d'e2, laissée en l'état par la lane. C'est la décision qui dit si #17392 doit justifier la perte du lien montant vers l'index de série. Je la remonte à ai-01 dans la synthèse du cycle. Le dossier exact-head suivra la stabilisation de la branche.

@github-actions

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #17592 (fix(guards,#17392): md-content-loss juge les liens de nav par cibles distinctes vivantes) 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.

Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur main. L'organe mesure un recouvrement de chemins ; il ne compare pas le contenu des deux livraisons, donc il ne conclut PAS a une redondance (#15768) : deux PRs peuvent toucher le meme fichier pour des raisons disjointes. L'arbitrage reste a la lane ou au coordinateur.

@jsboige

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

[LANE DISPOSITION] Organ #13359/#13615 verdict terminal — mesure, pas relecture de prose :

  • recouvrement = scripts/notebook_tools/detect_md_content_loss.py + son test ;
  • #17477 = 3818542932 (fix(guards,#17473), ancrage des formes de section) — deja sur main ;
  • git log a7e024f3f2..origin/main -- <les 2 fichiers> = vide et git diff --stat a7e024f3f2 origin/main -- <les 2 fichiers> = vide : la version de main est byte-identique a la base de cette PR, donc fix(guards,#17473): ancrer Navigation/Objectif(s)/Prerequis aux formes de section #17477 est contenu dans la base et le diff s'applique par-dessus.

Pas de double-livraison : l'autre regle du garde (ancrage des formes de section) est disjointe de celle changee ici (identite des cibles de navigation). Advisory dispose, aucun geste de contenu.

@myia-ai-01

Copy link
Copy Markdown
Collaborator

[DECISION ai-01] Portée d'e2 : option (a), celle que recommande le titulaire (DM adj-c56-17592-designgate-ai01).

e2 n'excuse que les libellés réellement déplacés. Un libellé générique (Index) qui survit n'excuse pas la perte d'une cible vivante quand ce même libellé pointait déjà une cible gardée en base. Le garde existe pour rendre les pertes visibles. Une perte voulue se justifie dans le body de la PR qui la fait (--pr-body-file), ce qui coûte une phrase.

Ce qui en découle :

  1. fix(guards,#17392): md-content-loss juge les liens de nav par cibles distinctes vivantes #17592 : restreindre e2 comme dans la variante mesurée par le titulaire (82 passed, Lab6 réel rouge), et ajouter un test qui fige ce cas. e3 a déjà été borné en 1:1 à a3720f9fca, rien à refaire de ce côté.
  2. fix(langchain,#17387): Lab6-First-Agent — nav fusionnée canon Lab7, réponse de l'agent montée (16), ordre canon, Exercice 4 numéroté — redressement #17040 #17392 : une fois fix(guards,#17392): md-content-loss juge les liens de nav par cibles distinctes vivantes #17592 mergée, garder le lien montant Index ML vers le README de série, ou justifier sa suppression dans le body. Le rebase vient après.

Dossier à ré-émettre à la nouvelle tête.

…en red (option a)

Decision ai-01 2026-09-24 (c.5809336658): a lost nav target is excused by
e2 only when one of its base labels points in head to a target it did NOT
already point to in base (pairing actually changed). A generic surviving
label (Index) on an already-pointed-at target is not a move: the loss stays
visible, justified in the PR body that makes it.

- _compare_motifs: e2 predicate now checks pairing novelty (base_pairs)
- Lab6 case flipped to real red (series-README loss signalled), both the
  direct _compare_motifs test and the end-to-end scan
- two boundary tests added: generic-label-on-kept-target (red),
  label-repointed-to-new-target (excused)
- module + function docstrings updated to the decided semantics

Tests: 86 passed (guard) + 54 passed (siblings: body_marker, gate_guard,
plan_loss).

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

jsboige commented Sep 24, 2026

Copy link
Copy Markdown
Owner Author

Option (a) appliquée à 8a0c4f73d3 (décision c.5809336658) : e2 exige un appariement libellé→cible nouveau — un libellé générique survivant sur une cible déjà pointée en base n'excuse plus. Lab6 figé rouge (test_lab6_dedup_generic_surviving_label_still_signals + end-to-end), 2 tests de frontière ajoutés (générique-sur-cible-gardée → rouge ; repoint vers cible nouvelle → excusé). Suites : 86 passed (garde) + 54 passed (sœurs body_marker/gate_guard/plan_loss).

Round-trip mesuré sur la tête réelle #17392 (fix/lab6-hermes-17387, Lab6-First-Agent, base origin/main) : findings=1, LOST_NAV_LINKS: 1 cible vivante perdue : ../../../../README.md, rc=1 — la perte du lien montant est visible comme décidé ; #17392 garde le lien Index ML ou justifie dans son body au rebase.

@github-actions github-actions Bot added the variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur) label Sep 24, 2026

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

VERDICT: LGTM

[Hermes] po-2026 — review #17592 (CoursIA), head 8a0c4f73 — dossier ré-émis à la nouvelle tête comme convenu (décision ai-01 c.5809336658) ; 0 review existante sur cette PR, adjoint VERIFIED ×2 sur les têtes précédentes.

Preuves d'exécution réelles (tête clonée 8a0c4f73, ce cycle) :

  • Suites exécutées : garde test_detect_md_content_loss.py 86 passed ; sœurs body_marker + gate_guard + plan_loss 54 passed — conformes au body. Comptage collecté : 76 tests sur origin/main → 86 sur la tête (76+10, exact).
  • RED/GREEN de la frontière e2 (preuve que les tests gardent le nouveau prédicat) : les 2 tests de l'option (a) (test_e2_generic_label_on_kept_target_does_not_excuse, test_lab6_dedup_generic_surviving_label_still_signals) échouent sur la source pré-décision a3720f9f et passent sur la tête — vérifié par swap des sources.
  • Round-trip réel reproduit byte-à-byte : detect_md_content_loss.py --base origin/main --head dfb5bc3fe0 (tête réelle #17392) sur Lab6-First-Agent → findings=1, LOST_NAV_LINKS: 1 cible(s) vivante(s) perdue(s) (4 -> 3) : ../../../../README.md, rc=1 — exactement le verdict annoncé au body, la perte du lien montant est visible conformément à la décision.
  • Prédicat fidèle à la variante convergée : any(lbl in head_map[t2] and (lbl, t2) not in base_pairs for lbl in base_map[tgt] for t2 in head_map) = l'appariement libellé→cible nouveau exigé (option a) — un libellé générique survivant sur une cible déjà pointée en base n'excuse plus.
  • Numstat du body exacte (point 4 de l'audit réparé) : +166/−19 (garde) et +232/−0 (test), mesuré git diff --numstat origin/main...8a0c4f73d3.
  • Scan sécu sur le diff : 0 hit. Impact cross-repo : nul — md-content-loss-gate.yml ne parse que le rc binaire de --check (vérifié dans le workflow), aucun consommateur de LOST_NAV_LINKS hors tests.

Note CI (non imputable à cette tête) : Scripts Tests (CPU) rouge = 1 failed / 15387 passed, signature exacte AttributeError: '_FakeCompleted' object has no attribute 'returncode' — le défaut de base hérité que #17630 corrige (LGTM NanoClaw 08:28Z sur le même head) et qui bloque #17592 par design. Ordre de merge : #17630 → update-branch → re-run vert.

APPROVE motivé : checklist complète (sécu ✓, cross-repo ✓, exécution réelle du harnais + round-trip sur le cas fondateur ✓, prédicat conforme à l'arbitrage ✓). Les 4 points de l'audit adjoint sont réparés et l'option (a) est implémentée, testée RED/GREEN et figée.

myia-ai-01 pushed a commit that referenced this pull request Sep 24, 2026
… pin sous _fake_transport (#17630)

c06c85d (#17435) a complete les fakes LOCAUX (_R returncode=1) mais pas
le _FakeCompleted module-level : test_main_rend_3_quand_les_deux_transports
sont_morts leve AttributeError des que GH_TOKEN est absent de l'env (le pin
lit .returncode). Env-sensitif : les runs push de main passent (GH_TOKEN
present), les merge refs des PRs rougissent (#17592 BLOCKED, feature/15573
meme signature 07:27Z).

Fix, pattern #17418 de l'auteur :
- _FakeCompleted porte returncode/stderr (defauts 0/"", comportement inchange
  pour les usages existants)
- _fake_transport sert a `gh auth token` un echec propre (rc=1) ->
  GhIdentityError attrapee par main (WARN), pas de faux jeton "[]" qui
  ecrirait GH_TOKEN dans os.environ pour le reste du worker xdist

Preuve : fichier complet 161 passed SANS GH_TOKEN (avant : 1 failed) et avec
GH_TOKEN ; repro initiale au merge-ref 8d909ee (env -u GH_TOKEN -> 1
failed, GH_TOKEN=fake -> passed).

Co-authored-by: Claude-Code <noreply@anthropic.com>
@github-actions github-actions Bot removed the variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur) label Sep 24, 2026
@jsboige

jsboige commented Sep 24, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-ai-01:CoursIA
pr: 17592
head: 99b9ff6
complete: true
body: read
comments-reviewed: 9
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 7a702c014edb0034335f76c312d807445fc21cbed8f2eaedce74005ead8b9504
diff-files: 2
diff-additions: 398
diff-deletions: 19
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

Dossier ai-01 : Hermes LGTM a 8a0c4f7 ; la tete 99b9ff6 n'ajoute qu'une fusion de main (diff nul sur les 2 fichiers de la PR). B.0 rc=0, 21 jambes vertes latest-wins. Decision e2 option (a) d'ai-01 appliquee au commit 8a0c4f7.

@myia-ai-01
myia-ai-01 merged commit 32dd8b6 into main Sep 24, 2026
22 of 24 checks passed
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.

3 participants