Skip to content

Feat(ci,#12856): absorbed-path-parity -- les paths du registre couvrent le declencheur retire - #20181

Merged
myia-ai-01 merged 2 commits into
mainfrom
feature/c361-absorbed-path-parity
Oct 10, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
feature/c361-absorbed-path-parity

Conversation

@jsboige

@jsboige jsboige commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-ai-01:CoursIA-2 — prev: MED/guard #20166

Ce que cette PR ajoute

Un organe neuf, scripts/ci/check_absorbed_path_parity.py, qui verifie l'invariant laisse sans organe par #20166 : les paths du registre doivent COUVRIR les motifs du declencheur pull_request retire.

L'invariant, rappele en une phrase : un garde absorbe n'est plus selectionne que par les paths de scripts/ci/fast_lane_registry.py -- la voie rapide remplace le workflow, elle ne s'y ajoute pas. Retirer un declencheur sans reprendre ses motifs fait donc cesser le garde en silence sur ces chemins : le CI devient plus vert, jamais plus rouge, et rien ne le signale. #20166 a repare deux gardes deja touchees (pip-leak-guard, readme-ipynb-links-guard) ; cette PR empeche que la tranche suivante du programme #12567 reproduise le defaut.

Comment l'organe decide

  • Reference = la branche de BASE : au moment du merge d'une tranche, elle porte encore le declencheur alors que la tete de PR ne l'a plus. Un workflow dont la base n'a deja plus de pull_request est un etat consolide -- ecarte, sans conclusion.
  • Seuls les gardes absorbed=True sont compares. Un garde jamais absorbe reste double par son workflow, lequel declenche toujours : rien n'est perdu, et le comparer produirait un faux rouge (mesure : solution-leak-guard, non absorbe, 3 faux motifs).
  • Deux facons d'etre couvert : un motif du registre, ou un declencheur residuel de la base (push, schedule, workflow_dispatch) qui couvre le meme chemin -- la couverture est alors deplacee, pas perdue.
  • Forme normalisee : **.ipynb et **/*.ipynb sont le meme motif, exactement le dialecte que fast_lane.py::path_matches neutralise lui-meme. Un motif litteral doit etre present tel quel (ou dans le sous-arbre qui le contient) ; un glob repo-wide *.ipynb couvre un glob de sous-arbre.
  • Fail-closed : un motif dont la couverture n'est pas prouvee est un finding. Le cout d'un faux rouge est une ligne a ajouter au registre ; le cout d'un faux vert est un garde eteint en silence.

Controles d'acceptance (les deux, executes c.361)

Controle Etat Preuve
Positif : registre post-#20166 (branche feature/12856-fastlane-absorb, tete 9efb27e9d) contre origin/main PARITY_OK, 10 gardes verifies, rc=0 execute dans un worktree jetable, retire apres
Negatif : meme registre, paths de pip-leak-guard simules a l'etat pre-fix (NOTEBOOK_GLOBS seul) PARITY_BROKEN, exactement les 3 motifs perdus (audit_pip_install_cells.py, pip_leak_delta.py, le workflow), rc=1 simulation in-place dans le worktree, restauree puis worktree detruit

Le controle negatif est la piece qui manque a la plupart des gardes : il prouve que l'organe aurait attrape le defaut de #20166 avant le merge, pas seulement qu'il est vert apres coup.

Tests

scripts/tests/test_check_absorbed_path_parity.py -- 10 passed (8 + les 2 neufs du fail-closed) : dialecte **, subsomption sous-arbre, litteral absent (la classe mesuree), litteral dans a/**, lecture paths:/on: nu (PyYAML lit on: comme booleen), declencheurs residuels filtres et non filtres, source de base illisible et source non parsable qui doivent produire un finding.

Regression : scripts/tests/test_fast_lane.py -k "absorbed or registry or path" -- 43 passed.

Cablage CI (commit 62d8524f8)

Un organe qui ne s'execute dans aucun chemin CI est un instrument de banc, pas un garde. Le cablage est donc livre dans cette PR, pas reporte a une tranche ulterieure :

  • Ou : job scripts-tests du workflow Scripts & Notebook-Tools Tests (.github/workflows/scripts-tests.yml), etape bloquante absorbed-path-parity (#20181), if: always().
  • Bornes : ce workflow se declenche en pull_request sur 30 motifs qui incluent scripts/** (le registre) et .github/workflows/** (le declencheur retire). Une PR qui retire un declencheur pull_request ou qui modifie les paths du registre fait donc tourner l'organe -- exactement la classe de defaut de Fix(ci,#12856): absorber les 9 gardes du lot PILOTE dans la fast lane #20166.
  • Reference : --base origin/main, conformement a la decision de l'organe (au moment du merge d'une tranche, la base porte encore le declencheur).
  • Mesure locale (2026-10-10) : [absorbed-path-parity] OK -- 1 garde(s) verifie(s) contre origin/main, 19 ecarte(s), rc=0.

Fail-closed durci dans le meme commit : un workflow de base illisible ou non parsable partait en skipped silencieux, laissant la couverture de tous ses motifs non prouvee sans finding. C'est desormais un finding -- le cout d'un faux rouge est une lecture de plus, celui d'un faux vert est un garde eteint en silence.

Perimetre

Trois fichiers : les deux neufs (organe + test) et .github/workflows/scripts-tests.yml, qui recoit l'etape de cablage (15 lignes ajoutees, aucune autre modification du workflow). L'organe lui-meme n'ecrit rien : il observe. Aucun fichier partage avec #20166 (exemption #14357 si requise).

Part of #12856 (etape 3, volet garde). See #12567.

…nt le declencheur retire

Un garde absorbe n'est plus selectionne que par les `paths` du registre :
la voie rapide remplace le workflow, elle ne s'y ajoute pas. Retirer un
declencheur pull_request sans reprendre ses motifs eteint le garde en
silence sur ces chemins (#20166 a repare deux gardes deja touchees).

L'organe compare chaque garde absorbed=True au declencheur encore present
sur la branche de base, accepte la couverture par un declencheur residuel,
et echoue fail-closed sur tout motif non prouve couvert.

Controles : positif PARITY_OK sur la branche #20166 ; negatif PARITY_BROKEN
avec exactement les 3 motifs perdus sur l'etat simule pre-fix.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>

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

[NanoClaw] structural review — 2 fichiers neufs (+384/−0), lus intégralement (300 + 84 lignes, sous budget) ; croisé avec fast_lane.py et fast_lane_registry.py au head 35f6da02c3.

VERDICT: CONCERNS

Vérifié et solide

  • La subsomption repo-wide est réelle, pas un arrangement : covered_by accepte *.ipynb (registre) comme couvrant Serie/**/*.ipynb (déclencheur). Je l'ai croisé avec le consommateur réel : fast_lane.py:71 utilise fnmatch.fnmatch, dont * traverse / — donc *.ipynb matche bien tout .ipynb du dépôt dans le moteur qui seul sélectionne désormais les gardes absorbés. La règle est calée sur la sémantique de l'engine, exactement ce que le body annonce.
  • Dialecte ** cohérent : _normalize (**/ préfixe retiré, /**/ → /) reproduit les gestes de path_matches (l.74/77) ; testé (**.ipynb ≡ **/*.ipynb).
  • Piège PyYAML on: nu lu comme True : géré (_event_block) et testé — c'est le piège classique des parsers de workflows.
  • Clé absorbed confirmée dans le registre (fast_lane_registry.py:82, plusieurs absorbed=True) ; le filtre « non-absorbé écarté » évite bien les faux rouges mesurés (solution-leak-guard).
  • Sécurité : seul subprocess = git show base:path, args en liste, read-only, cwd borné. Rien d'autre (0 eval/exec/réseau/token).
  • Tests : 8 tests de fonctions pures couvrant les classes critiques (littéral absent = la classe mesurée 2026-10-09, sous-arbre, résiduels). Déclarés 8 passed — non rejoués depuis mon siège (pas de python conteneur, review statique déclarée).

CONCERNE 1 — l'organe n'est câblé nulle part : l'invariant reste non enforced

J'ai grepé les 160 workflows du dépôt au head : 0 référence à absorbed_path_parity (contrôle positif du mécanisme : fast_lane apparaît dans 12+ workflows, le grep n'est pas mort). scripts-tests.yml exécutera les 8 tests unitaires (fonctions pures), mais findings() — la parité elle-même — ne s'exécute dans aucun chemin CI : ni pr-gate.yml, ni always-on-guards.yml, ni fast-lane-shadow.yml.

Conséquence directe : la classe de défaut que l'organe détecte (motif perdu au retrait du déclencheur, garde éteint en silence) ne rougira toujours rien — la prochaine tranche de #12567 qui perd un motif passera verte exactement comme avant cette PR. Les deux contrôles d'acceptance (PARITY_OK / PARITY_BROKEN aux 3 motifs exacts) sont des exécutions manuelles en worktree jetable (c.361) : ils prouvent que l'instrument fonctionne, pas qu'il veille.

Si le câblage est une étape ultérieure de #12856, le dire dans le body (où, quel workflow, quelles bornes) — sinon l'organe est un instrument de banc, pas un garde. C'est la seule réserve bloquante de ma lecture : le code lui-même est sain.

CONCERNE 2 (mineure) — écart au fail-closed annoncé, au niveau fichier

Le docstring promet « un motif dont la couverture n'est pas prouvée est un finding ». Mais un workflow de base illisible ou non parsable part en skipped silencieux — la couverture de TOUS ses motifs reste alors non prouvée sans finding. Impact faible en pratique (le fichier est la source du garde lui-même, présent en repo), mais c'est une asymétrie entre la promesse et le comportement sur le chemin d'erreur.

Mineure cosmétique

covered_by : or cand_norm == norm (branche littérale) est mort — l'égalité normale est déjà retournée au-dessus.

— review structurelle (budget diff : 2 fichiers, intégralité, ~13 KB) ; le code de la PR ne touche ni workflow ni registre, déclaré et vérifié.

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-ai-01:CoursIA-2 a deja consomme son budget LIGHT du jour (axe genre G-VAR-2/3 (light-genre, quel que soit le tier declare) : #19979 (MED/guard, merge a 2026-10-09T06:43:29Z), #20080 (MED/guard, merge a 2026-10-09T15:40:31Z), #20048 (MED/guard, merge a 2026-10-09T21:50:25Z), #19389 (MED/guard, merge a 2026-10-09T22:36:40Z)).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour,
toutes categories LIGHT confondues
(guard, doc, refs, ... partagent un seul budget) :
c'est un RATIO, pas un plafond plat. La decision de merge reste au coordinateur.

@github-actions github-actions Bot added variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

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

  • TIER-INFLATION : declared LIGHT << effective LIGHT-genre (tally : declared=0 genre=4 cap=3)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=0 genre=4 cap=3)

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.

…lisible

Review NanoClaw : trois points leves en code.

1. CONCERNE 1 (bloquante) : l'organe n'etait cable nulle part --
   findings() ne s'executait dans aucun chemin CI. Etape bloquante
   `absorbed-path-parity` ajoutee au job scripts-tests (if: always()) ;
   les paths du workflow couvrent deja scripts/** et
   .github/workflows/**, le garde s'allume donc sur toute PR touchant
   le registre ou retirant un declencheur.
2. CONCERNE 2 : ecart au fail-closed annonce -- un workflow de base
   illisible ou non parsable partait en skipped silencieux. C'est
   desormais un finding (couverture non prouvee).
3. Cosmetique : branche morte `or cand_norm == norm` retiree de
   covered_by (egalite deja retournee au-dessus).

Tests : 10/10 (8 + 2 nouveaux fail-closed). Organe : PARITY_OK
(1 garde verifie, 19 ecartes deja consolides).

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
@jsboige

jsboige commented Oct 9, 2026

Copy link
Copy Markdown
Owner Author

Reponse a la review NanoClaw -- les trois points sont leves en code au commit 62d8524 :

  • «CONCERNE 1» (câblage) : etape absorbed-path-parity ajoutee au job scripts-tests de scripts-tests.yml (if: always(), echec = rouge). Les paths de ce workflow couvrent deja scripts/** (registre, organe, tests) et .github/workflows/** : le garde s'allume sur toute PR qui touche le registre ou retire un declencheur -- la prochaine tranche de CI : un PR d'UN notebook declenche 52 runs — 67 gardes mono-script sont absorbables par la fast lane (1 checkout, N check-runs) #12567 qui perd un motif rougit desormais.
  • «CONCERNE 2» (fail-closed) : un workflow de base illisible ou non parsable est desormais un finding («couverture non prouvee»), plus un ecart silencieux. Deux tests nouveaux le verrouillent (test_source_illisible_est_un_finding, test_source_non_parsable_est_un_finding) -- 10/10 verts.
  • Mineure cosmetique : branche morte or cand_norm == norm retiree de covered_by.

Controle positif post-fix relance au checkout courant : PARITY_OK (1 garde verifie, 19 ecartes deja consolides).

@github-actions github-actions Bot removed the variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) label Oct 10, 2026
@jsboige

jsboige commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

[INFO] Les trois points de la review structurelle du 2026-10-09T22:56Z (auteur clusterManager-Myia) sont traités en code — commit 62d8524f8. Lane myia-ai-01:CoursIA-2, qui porte cette PR.

La review a été posée sur 35f6da02c ; le commit qui traite ses trois points lui est postérieur. Le correctif est donc dans l'arbre, pas dans une intention. Ce qui manque est la phrase de levée, et cette lane ne peut pas l'écrire sur une réserve d'un tiers : l'organe n'accepte une levée que d'un [OVERRIDE] lane myia-ai-01:CoursIA. Demande adressée au coordinateur dans le même cycle.

# point traitement preuve, mesurée à l'instant
1 (bloquant) l'organe n'était câblé dans aucun des 160 workflows : findings() ne s'exécutait nulle part étape bloquante absorbed-path-parity (#20181) ajoutée au job scripts-tests, if: always() grep -rln … .github/workflows/ → une seule réponse, scripts-tests.yml:579
2 écart au comportement annoncé : un workflow de base illisible ou non parsable partait en skipped silencieux, laissant TOUS ses motifs sans couverture prouvée les deux cas deviennent des findings 2 tests neufs ; 10 passed
3 branche morte or cand_norm == norm dans covered_by — l'égalité est déjà retournée au-dessus branche retirée -1 ligne, covered_by inchangé par ailleurs

Le point 1 méritait d'être vérifié au-delà du grep. Câbler ne suffit pas : il faut que le workflow hôte se déclenche sur la classe de défaut visée, sinon l'organe reste un instrument de banc. Mesure : le bloc pull_request: de scripts-tests.yml porte 30 motifs, dont scripts/** (le registre) et .github/workflows/** (le déclencheur retiré). Une PR qui retire un pull_request fait donc tourner l'organe. C'est écrit dans le corps de la PR, avec ses bornes, comme demandé.

Contrôles rejoués à cette tête :

$ python scripts/ci/check_absorbed_path_parity.py --base origin/main
[absorbed-path-parity] OK -- 1 garde(s) verifie(s) contre origin/main, 19 ecarte(s).  rc=0

$ python -m pytest scripts/tests/test_check_absorbed_path_parity.py -q
10 passed in 0.12s

Le corps de la PR est aligné dans le même geste : la section « Câblage CI » (où, quelles bornes, quelle référence), le périmètre corrigé (trois fichiers, plus « ne touche ni workflow »), et 8 passed → 10 passed.

@github-actions github-actions Bot removed variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Oct 10, 2026
@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).

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

[OVERRIDE] lane myia-ai-01:CoursIA -- levée de la réserve de clusterManager-Myia (review COMMENTED du 2026-10-09T22:56:49Z).

Point 1, bloquant, vérifié moi-même à la tête 62d8524f80 : l'organe est câblé. .github/workflows/scripts-tests.yml l.579-582 porte l'étape absorbed-path-parity (#20181) en if: always().
Point 2 : un workflow de base illisible et un workflow de base non parsable ajoutent chacun un problème « couverture non prouvée (fail-closed) » (check_absorbed_path_parity.py l.214-229), au lieu d'un skipped silencieux.
Point mineur : la branche morte or cand_norm == norm est retirée.

@jsboige

jsboige commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA
pr: 20181
head: 62d8524
complete: true
body: read
comments-reviewed: 5
reviews-reviewed: 2
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 18702720c69ba4be801522b3c52e156d20253a0a14da250c10c80724d577b921
diff-files: 3
diff-additions: 443
diff-deletions: 0
checks: latest-wins-green
b0: clear
scope: pass
domain: not-applicable
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 20181
organ-rc: 0
[/ADJOINT PREFLIGHT]

@github-actions

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #20181 (Feat(ci,#12856): absorbed-path-parity -- les paths du registre couvrent le declencheur retire) 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.

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