Skip to content

fix(ci,#19168): absorber TRANCHE15/16 et declarer l'ombre du lot pilote - #19171

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/19168-shadow-blocking-guards
Oct 5, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/19168-shadow-blocking-guards

Conversation

@myia-ai-01

Copy link
Copy Markdown
Collaborator

Grain: MED/guard — lane myia-ai-01:CoursIA-2 — prev: MED/notebook-python #18536

Le defaut

Deux gardes declarees blocking=True dans scripts/ci/fast_lane_registry.py ne bloquaient rien. Le job « Always-on guards » lance python scripts/ci/fast_lane.py --shadow (always-on-guards.yml), et le moteur calcule effective_shadow = args.shadow and not guard.absorbed : un garde non absorbe emet sous fast-lane (ombre): avec une conclusion neutre et n'entre pas dans blocking_failed. Le registre annoncait « bloquant », le rollup disait « ombre ».

Mesure de l'issue reproduite sur control-chars-in-cells-guard, meme garde et rc=1 :

nom emis conclusion compte dans blocking_failed
avant fast-lane (ombre): control-chars-in-cells-guard neutral non
apres control-chars-in-cells-guard failure oui

Les deux gardes absorbees

Les deux sont vertes sur main, verifie avant absorption — absorber ne rougit donc aucune PR existante par dette heritee :

  • lake-direct-invocation-guard : check_lake_direct_invocation.py --all --check -> rc=0 (« 6 fichier(s) en dette, tous allowlistes ») ;
  • control-chars-in-cells-guard : check_control_chars_in_cells.py --diff origin/main...HEAD -> rc=0.

check_absorbed_check_run_identity.py --check reste vert sur la branche (rc=0, 16 gardes absorbes byte-identiques a leur source). Note : cet organe enumere les tranches 1 a 5 ; ses deux nouveaux gardes sont natifs de la voie rapide, donc sans workflow d'origine a qui etre identiques — la verification y est vacue par construction, pas contournee.

L'ombre du lot pilote est desormais DECLAREE

L'issue offrait deux voies : absorber, ou ecrire dans le registre que la garde est volontairement en ombre avec son motif et son critere de bascule. Les 15 gardes pilotes bloquantes non absorbees sont declarees, et la mesure du 2026-10-05 montre trois situations distinctes — deux d'entre elles sont inertes aujourd'hui, et c'est un constat, pas une intention :

Situation Gardes Pourquoi l'ombre est legitime
Workflow d'origine qui declenche encore sur pull_request 9 c'est lui qui bloque ; la voie rapide observe. Bascule : absorber quand ce declencheur sera retire (programme #12567)
Workflow d'origine SANS pull_request 2 (perimeter-review-guard, self-hosted-runner-policy) aucun autre emetteur du nom de check-run
Garde natif de la voie rapide 4 (hr-substitution-guard, duplicate-notebook-index-guard, kernel-suffix-canon-guard, slot-reservation-guard) aucun workflow d'origine, donc aucun autre emetteur

Les 6 gardes des deux dernieres lignes sont inertes exactement comme l'etaient TRANCHE15/16. Elles sont declarees, pas reparees : basculer le lot pilote entier est le geste du programme #12567, pas celui de cette correction. Le motif et le critere de bascule vivent dans shadow_reason (nouveau champ de Guard).

Le test qui ferme la classe

test_aucun_garde_bloquant_n_est_inert_sans_declaration parcourt tout le registre (PILOT + tranches, decouvertes dynamiquement) et exige, pour chaque garde bloquant, l'un des deux etats : absorbe, ou declare en ombre. Un absorbe qui porte encore un shadow_reason est signale comme declaration perimee. Deux controles positifs (absorbes et declares non vides) empechent le test de devenir vrai en silence.

Falsifiabilite mesuree : retirer absorbed=True de TRANCHE16 rougit le test, qui nomme control-chars-in-cells-guard dans son message ; registre restaure depuis backup et verifie byte-identique.

Un defaut d'isolation revele au passage

Absorber TRANCHE16 a fait echouer test_mixed_emission_pilot_stays_shadowed_and_non_blocking, et la cause n'est pas la garde : le helper _drive_mixed_emission ne vidait que PILOT, TRANCHE1, TRANCHE2, TRANCHE4 et TRANCHE5, laissant tourner les gardes reelles de douze tranches dans un test qui annonce une lane a deux gardes. Leur rc etait injecte par le faux run_argv, donc une tranche absorbe et bloquante rendait rc=1 et faisait rougir le job. Le test passait par accident tant qu'aucune tranche oubliee n'etait absorbe et bloquante. Le helper vide desormais toute tranche decouverte dynamiquement (vars(fl) filtre sur TRANCHE).

Preuves

  • pytest scripts/tests/test_fast_lane.py scripts/tests/test_check_absorbed_check_run_identity.py scripts/tests/test_pr_gate.py scripts/tests/test_check_control_chars_in_cells.py scripts/tests/test_fast_lane_merge_base.py -q -> 250 passed
  • falsifiabilite du nouveau test : mesuree (mutation rouge nommant la garde, restauration verte)
  • gardes vertes sur main avant absorption : rc=0 pour les deux
  • check_absorbed_check_run_identity.py --check -> rc=0

Ce que cette PR ne fait pas

See #19168 — les criteres de cloture de l'issue sont couverts ; la fermeture reste au coordinateur.

🤖 Generated with Claude Code

Deux gardes declarees `blocking=True` ne bloquaient rien : le job
« Always-on guards » lance `fast_lane.py --shadow`, et le moteur calcule
`effective_shadow = args.shadow and not guard.absorbed`. Sans absorption,
elles emettaient sous `fast-lane (ombre): ` avec une conclusion NEUTRE et
n'entraient pas dans `blocking_failed`.

Absorbees, apres verification qu'elles sont vertes sur `main` (donc sans
rougir aucune PR existante par dette heritee) :
  - `lake-direct-invocation-guard` (`--all --check` -> rc=0, 6 fichiers en
    dette tous allowlistes) ;
  - `control-chars-in-cells-guard` (`--diff origin/main...HEAD` -> rc=0).

Temoin du basculement, meme garde et `rc=1` :
  avant : nom `fast-lane (ombre): control-chars-in-cells-guard`, conclusion
          `neutral`, hors `blocking_failed`
  apres : nom `control-chars-in-cells-guard`, conclusion `failure`, compte
          dans `blocking_failed`
C'est exactement le critere de cloture de l'issue (nom canonique sur une PR
de notebooks, et un diff violant la garde rougit « Always-on guards »).

Declare l'ombre du lot pilote. Mesure du 2026-10-05 sur les 15 gardes
pilotes bloquantes non absorbees :
  - 9 ont un workflow d'origine qui declenche encore sur `pull_request` :
    c'est lui qui bloque, la voie rapide observe ;
  - 2 ont un workflow d'origine qui ne declenche PAS sur `pull_request`
    (`perimeter-review-guard`, `self-hosted-runner-policy`) : aucun autre
    emetteur de leur nom de check-run ;
  - 4 sont natives de la voie rapide : meme situation, sans workflow.
Les deux dernieres categories sont donc inertes aujourd'hui -- declarees ici
avec leur critere de bascule, pas reparees : basculer le lot pilote entier
est le geste du programme #12567, pas celui de cette correction.

`shadow_reason` (nouveau champ de `Guard`) porte le motif ET le critere de
bascule, ce que l'issue demande comme seconde voie. Le test
`test_aucun_garde_bloquant_n_est_inert_sans_declaration` ferme la classe
entiere : tout garde bloquant doit etre absorbe ou declare, et un absorbe qui
porte encore un motif d'ombre est signale comme declaration perimee.

Defaut d'isolation revele et repare au passage : `_drive_mixed_emission` ne
vidait que PILOT, TRANCHE1, 2, 4 et 5 -- les gardes REELLES de douze tranches
tournaient dans un test qui annonce une lane a deux gardes, avec leur rc
injecte par le faux `run_argv`. Le helper vide desormais toute tranche
decouverte dynamiquement.

Preuves :
- `pytest scripts/tests/test_fast_lane.py scripts/tests/test_check_absorbed_
  check_run_identity.py scripts/tests/test_pr_gate.py scripts/tests/test_check_
  control_chars_in_cells.py scripts/tests/test_fast_lane_merge_base.py -q`
  -> 250 passed
- falsifiabilite : retirer `absorbed=True` de TRANCHE16 rougit le nouveau
  test, qui nomme `control-chars-in-cells-guard` ; fichier restaure depuis
  backup et verifie byte-identique
- `check_absorbed_check_run_identity.py --check` -> rc=0 (16 gardes absorbes
  byte-identiques)

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

github-actions Bot commented Oct 4, 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) : #18991 (MED/guard, merge a 2026-10-04T02:12:45Z), #19008 (DEEP/guard, merge a 2026-10-04T02:49:01Z), #19017 (DEEP/guard, merge a 2026-10-04T06:18:40Z), #19021 (DEEP/guard, merge a 2026-10-04T06:32:45Z), #19075 (LIGHT/guard, merge a 2026-10-04T10:37:36Z), #19108 (MED/guard, merge a 2026-10-04T14:36:47Z), #19105 (MED/guard, merge a 2026-10-04T14:39:27Z), #18761 (MED/guard, merge a 2026-10-04T21:47:38Z)).
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 4, 2026
@github-actions

github-actions Bot commented Oct 4, 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-04) :

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

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.

@github-actions

github-actions Bot commented Oct 4, 2026

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

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #19171 (fix(ci,#19168): absorber TRANCHE15/16 et declarer l'ombre du lot pilote) 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.

@jsboige

jsboige commented Oct 5, 2026

Copy link
Copy Markdown
Owner

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-ai-01:CoursIA
pr: 19171
head: 2cc4ff5
complete: true
body: read
comments-reviewed: 4
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: f56d3928a28703c4b4155a8b71150d1f8ae90953d44693c7e3be4cbb3e472a96
diff-files: 2
diff-additions: 134
diff-deletions: 3
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 19171
organ-rc: 0
[/ADJOINT PREFLIGHT]

Dossier tiers (ai-01:CoursIA), à la tête 2cc4ff5755. CI (scripts/ci/), sans notebook.

@myia-ai-01
myia-ai-01 merged commit 85c67ed into main Oct 5, 2026
28 of 29 checks passed
myia-ai-01 added a commit that referenced this pull request Oct 5, 2026
…eclaree des natifs + temoin negatif (#19207)

* ci(fast-lane,#19193): decouverte dynamique des tranches + exemption declaree des natifs + temoin negatif

Le filet d'identite byte-a-byte (`check_absorbed_check_run_identity.py`)
enumerait 5 tranches en dur (TRANCHE1..5) -- un garde absorbe d'une
tranche 6+ etait silencieusement non verifie. Le constat fondateur :
TRANCHE10, 14, et le lot pilote (12 gardes) etaient hors du filet.

Trois changements :

1. Decouverte dynamique via `vars(reg)` : on enumere chaque liste de
   `Guard` du registre. Une nouvelle TRANCHE18 sera couverte sans toucher
   au filet. Le pattern vient de `test_aucun_garde_bloquant_n_est_inert
   _sans_declaration` (#19171, TRANCHE17).

2. Exemption declaree des gardes `source == FAST_LANE_NATIVE` (natifs de
   la voie rapide) : signalee en sortie (pas un saut silencieux). 14
   gardes concernes.

3. Témoin negatif : un test injecte un garde dont le nom ne matche
   pas le job du workflow source, et verifie que le filet le detecte.

Deux exemptions de programme documentees en sortie :
- `PILOT` (12 gardes) : absorption par declaration, programme #12567
- `TRANCHE10` (1 garde) : absorption faite mais job.name source non
  aligne, programme #12567

Couverture finale mesuree (run 2026-10-05) :
- 19 gardes absorbes byte-identiques a leur source (TRANCHE1..9+11..17)
- 14 gardes natifs exemptes
- 12 gardes du lot pilote exemptes (programme #12567)
- 1 garde en cours d'alignement (programme #12567)

Travail prolonge directement #19171. Grain MED/guard.

Grain: MED/guard -- lane myia-po-2025:CoursIA-2 -- prev: MED/guard #19171

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

* fix(fast-lane,#19193): import the exemption constants from the registry

Hermes finding on PR #19207 (review 5409874260): the filet kept local
copies of PILOT_LOT_NAME and ALIGNMENT_EN_COURS instead of importing
them, so retiring TRANCHE10 from the registry would leave the net
green for the wrong reason. The net now reads the registry constants
under their registry names; local copies removed. Behavior verified
unchanged: 15/15 tests, filet rc=0, same counts (19 byte-identical,
14 natifs, 12 pilote, 1 alignement #12567).

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

---------

Co-authored-by: jsboige <jsboige@gmail.com>
Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
@jsboige
jsboige deleted the fix/19168-shadow-blocking-guards branch October 7, 2026 07:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants