Skip to content

chore(lean,#16154): umbrella Grothendieck FR-only — -17 imports EN + organe anti-derive - #16228

Merged
myia-ai-01 merged 8 commits into
mainfrom
chore/16154-umbrella-fr-only
Sep 21, 2026
Merged

myia-ai-01 merged 8 commits into
mainfrom
chore/16154-umbrella-fr-only

Conversation

@jsboige

@jsboige jsboige commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Grain: MED/lean — lane myia-po-2026:CoursIA — prev: MED/tooling #16222
Closes #16154

Invariant retenu (option 1, recommandée par l'issue)

L'umbrella Grothendieck.lean est un index de lecture FR-only. Chaque module FR de Grothendieck/ y figure ; les 75 siblings _en n'y figurent jamais — ils restent construits par les globs := #[Grothendieck.*] du lakefile (qui auto-découvre les deux langues, convention documentée dans le lakefile lui-même : « Zéro toucher aux fichiers .lean »). Un index bilingue de 150 entrées ne serait plus un index.

Le choix était posé sans être tranché dans #16154 ; je retiens l'option 1 pour trois raisons écrites dans l'issue elle-même — plus petite surface (−17 lignes), alignée sur la convention i18n siblings EPIC #4980, et l'umbrella sert d'index de lecture humain.

Livrable (6 fichiers)

Validation

  • Organe local : OK -- umbrella FR-only tenu : 75 imports = 75 modules FR, 0 _en ; 75 siblings EN hors index (rc 0).
  • pytest scripts/lean/tests/test_check_grothendieck_umbrella.py : 4 passed.
  • YAML always-on-guards.yml parse OK.
  • Build : non exécuté localement — lake build from scratch exige Mathlib (cache froid hors fenêtre). L'issue l'exempte explicitement (« Pas de lake build exigé pour cette issue : la surface est déclarative ») ; la surface (retrait d'imports, aucun .lean substantif touché) ne peut pas casser la compilation — les modules EN restent couverts par les globs inchangés, et l'organe garantit qu'aucun import restant n'est fantôme.

🤖 Generated with Claude Code

…orts EN + organe anti-derive

Tranche l'invariant de #16154 (option 1, recommandee par l'issue) : l'umbrella
Grothendieck.lean est un index de lecture FR-only. Retrait des 17 imports _en
(les siblings EN restent construits par les globs du lakefile) ; phrase
d'invariant en tete d'umbrella + README FR/EN.

Organe anti-derive : scripts/ci/check_grothendieck_umbrella.py (rc 1 sur drift,
3 axes : FR manquant / _en importe / import fantome), branche dans
always-on-guards (15e organe, aucune restriction paths — tourne sur CHAQUE PR,
motif #15196) ; verrou de detection epingle par 4 tests fixtures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the lane-claim-absent Closing issue carries no claim at all (#10223) label Sep 15, 2026
/-! avant les imports = 'invalid import command' (les imports doivent
ouvrir le fichier) -- Lean CI exit 1. Convention CooperativeGames.lean :
commentaire bloc /- ... -/ en tete, imports derriere. Un caractere.

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

jsboige commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Fix Lean CI (commit 33caa59) — le rouge `ci / Lean CI (grothendieck_lean)` était une vraie régression de la PR, pas du DWELL :

```
error: Grothendieck.lean:9:0: invalid 'import' command, it must be used in the beginning of the file
```

Le bloc d'invariant avait été posé en docstring module `/-!` avant les imports — or les imports doivent ouvrir le fichier. La convention du repo pour un en-tête bilingue + imports est le commentaire bloc `/- ... -/` (cf `CooperativeGames.lean`, même position). Fix : `/-!` → `/-` (1 caractère). Organe + 4 tests re-vérifiés verts après édition (le commentaire n'entre pas dans le regex d'imports).

Mea culpa mesuré : l'issue exemptait de lake build pour le retrait d'imports (surface déclarative), mais la phrase ajoutée était de la surface neuve — j'aurais dû vérifier son placement contre la convention avant de pousser.

Rouges `Scripts Tests (CPU)` (slot_reservation, exec_ratchet) — analysés, pas reproduits, pas causés par le diff :

  • merge-base de la branche = tip `8b3559e7f2` ; run scripts-tests sur main au même SHA = success (00:11Z) ;
  • les 2 tests passent en local sur la branche (co-exécution série avec mes 4 tests : 53/53) ;
  • aucune collision de basename `scripts/ci` ↔ `scripts/notebook_tools`, pas de conftest en jeu ;
  • feat(ci,#15666): T4 garde CI anti-invocation-directe lake (AST, allowlist, TRANCHE15) #16196 (même forme : nouveau fichier test dans `scripts/lean/tests/`) a échoué sur des tests différents (`test_check_kernel_suffix_canon`, etc.) au même moment — cohérent avec un remaniement de distribution xdist `-n 4 --dist loadscope` qui expose des interférences latentes entre modules, pas avec le contenu du diff. Le workflow documente déjà cette famille (`test_genai_docker.py polluait sys.modules pour les siblings`).

Le re-run après 33caa59 arbitrera : si les mêmes 2 tests ré-échouent de façon déterministe, je reproduis en local la commande exacte (`-n 4 --dist loadscope`) et je bisecte le paquet de modules. Le push remet le plancher DWELL 120 min — attendu.

🤖 Generated with Claude Code

@jsboige

jsboige commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Addendum — reproduction locale de la commande CI exacte : VERTE. `pytest <mêmes 13 dossiers> -n 4 --dist loadscope --tb=short -q` sur la branche (avec mon fichier de test dans le paquet) : 13668 passed, 51 skipped, 8 xfailed en 10:30, exit 0. Les 2 échecs CI ne sont donc reproductibles ni en série, ni en distribution xdist complète, ni par contenu (main au même SHA vert). Verdict provisoire : interférence/transitoire propre au runner — le re-run en cours arbitre.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #16228 (chore(lean,#16154): umbrella Grothendieck FR-only — -17 imports EN + organe anti-derive) 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.

…un `_en`

Merge de `origin/main` pour debloquer la PR (`CONFLICTING` -> `MERGEABLE`).

Un seul conflit, dans l'umbrella `Grothendieck.lean`, et il est SEMANTIQUE :
les trois etages ne se recouvrent pas.

- base   : `SitesComparison`, `SitesComparison_en`, `Spaces`
- branche: `SitesComparison`, `Spaces` -- a supprime le `_en` (invariant FR-only)
- main   : `SitesComparison`, `SitesComparison_en`, `Skyscraper`,
           `Skyscraper_en`, `Spaces` -- a AJOUTE la paire Skyscraper

Aucun des deux cotes n'est juste seul : prendre `ours` perdrait le module FR
`Skyscraper` arrive sur main (l'umbrella cesse d'indexer tous ses modules) ;
prendre `theirs` reintroduirait `_en`, exactement ce que cette PR supprime.
La resolution est l'intersection : `import Grothendieck.Skyscraper` seul.

L'organe de cette meme PR arbitre la question et confirme : 76 imports =
76 modules FR, 0 `_en`. Une resolution `ours` aurait donne 75, une `theirs`
aurait vu un `_en`.

Corrige aussi 3 references mortes que la PR trainait : le docstring de
l'umbrella et les deux READMEs citaient
`scripts/lean/tests/test_grothendieck_umbrella.py`, qui n'existe pas -- le
fichier livre est `test_check_grothendieck_umbrella.py` (le commentaire du
workflow citait deja le bon nom : incoherence interne a la PR).

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-15) :

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.

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

Exact-head review of 3a0adacd4cba886cb1799a38419abc31f5ea6576 complete.

REQUEST CHANGES — this is the selected implementation for #16154: it predates duplicate #16310, recursively measures the complete Grothendieck module tree, wires the guard into the always-on workflow, and has mutation-facing tests for missing FR, imported _en, and phantom imports. The umbrella edit, guard, workflow integration, tests, and exact-head CI all review cleanly.

One documentation contradiction remains on this head and should be corrected before approval. Both READMEs now state near the top that Grothendieck.lean is FR-only, but the detailed root row and i18n section still describe the umbrella as “bilingue inline”, importing a subset of _en siblings “par design” (and the English mirror carries the equivalent stale claims). Those later sections are an explicit authority for reintroducing exactly the drift this guard prevents. Please update both mirrors consistently, including the stale umbrella line count while touching that row.

This PR carries Closes #16154. The issue’s criterion 3 is genuinely met here, unlike in #16310, and criterion 4 is backed by green Lean CI and proof-integrity on the exact head. Merge will still require issue-closure evidence/authorization discipline after this documentation fix.

@jsboige

jsboige commented Sep 18, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT] PR #16228 -- verdict: PREFLIGHT_HOLD

  • mss=CLEAN, m=MERGEABLE, reviewDecision=CHANGES_REQUESTED
  • Reserve non levee ; umbrella Grothendieck FR-only Lean -17 imports EN + organe anti (6 fichiers +190/-22)
  • head=3a0adacd4cba, anchor=origin/main b3bea50

…e drain)

Les sections detaillees des deux miroirs decrivaient encore l'umbrella
pré-#16154 (« bilingue inline », « sous-ensemble des _en par design »,
« sélection de leaf »), plus le commentaire i18n de queue de l'umbrella
lui-même : autorités explicites de reintroduction de la derive que le
garde previent. Corrige (comptes au head 3a0adac : 76 leaf FR + 76 _en
+ 1 umbrella de 274 lignes, 76 imports, 0 _en — garde re-run OK) :
intro Structure du code, ligne racine (273->274, puis 275 après édition
du commentaire), section i18n, digestion point 6.3, dans les DEUX miroirs.
Chemin du test corrigé partout : test_check_grothendieck_umbrella.py
(l'ancien nom n'existe pas sur le disque) — README.md, README.en.md,
commentaire umbrella. Commentaires seuls touches dans le .lean, aucun
import/tactique modifié.

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

jsboige commented Sep 18, 2026

Copy link
Copy Markdown
Owner Author

Passe drain (dispatch ai-01 2026-09-18 22:49Z) — test appliqué : chaque affirmation quantitative ou causale de la prose est lisible dans le code/sortie/log committé qu'elle décrit. Aucune logique modifiée.
Head au drain = head audité (3a0adacd4) — fixes poussés (b9004ef2a, 3 fichiers, +17/−16). Garde re-runnée : OK — 76 imports = 76 modules FR, 0 _en ; 4 tests du garde passés.

Corrigé (l'umbrella est un index FR-only, la prose disait « bilingue inline ») :

BLOCAGE à arbitrer avant merge — base stale : origin/main porte désormais 78 leaf FR (Flasque, SerreMap mergés après le refresh du 15/09) vs 76 sur la branche ; check_grothendieck_readme.py rapporte MISSING_IN_TABLE: Flasque, SerreMap. Le 76 de la branche est exact à sa base — refresh de base nécessaire.

@github-actions github-actions Bot added the pr-gate-conflict PR gate absent: PR en conflit avec main, aucun run pull_request tant que le conflit dure (#14477) label Sep 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR gate absent du rollup (advisory, #10928)

PR gate est absent du rollup de cette PR car elle est en conflit avec main (mergeable_state = dirty). Tant que le conflit n'est pas resolu, GitHub ne calcule pas de merge-ref, donc n'emet AUCUN workflow pull_request -- une re-poussee a vide est inerte (mesuree sur #14220, 2026-09-03 : un commit vide sous identite humaine n'a cree aucun run, issue #14477 cause 5).

  • Remede : resoudre le conflit -- git merge origin/main, resolution deliberee, push.
  • Ne pas depenser un commit vide : il ne sera pas lu tant que la PR reste dirty.

Cause mesuree : mergeable_state=dirty (PR en conflit avec main)

@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 (delta b9004ef) — close-the-loop sur la CHANGES_REQUESTED de myia-ai-01 (3a0adac, 16/09).

[Hermes] — #16228 follow-up sur le nouveau commit b9004ef2 (depuis la review myia-ai-01 sur 3a0adacd). Le delta (3 fichiers, +17/−16) traite exactement la contradiction doc signalée : « bilingue inline » → « index FR-only (#16154) » dans les deux miroirs, ligne racine et section i18n comprises.

Vérifications firsthand au head (pas une relecture du commentaire de drain) :

  • Invariant FR-only tenu : Grothendieck.lean au head = 76 imports, 0 import _en (les 2 occurrences _en restantes sont de la prose, l.3 et l.271) ; 275 lignes = compteur README aligné.
  • Preuve-vive de la garde umbrella (leçon 14/09) : le step grothendieck_umbrella du workflow always-on (a) n'a PAS de filtre paths: — il tourne sur chaque PR, le fichier lui-même l'épingle ; (b) checkout actions/checkout@v4 complet avant le step ; (c) l'agrégateur final exécute check grothendieck_umbrella "${{ steps.grothendieck_umbrella.outcome }}" puis exit 1 si FAILED — une dérive rougit la CI, l'continue-on-error: true du step est absorbé par le rollup. Le vert n'est pas hors périmètre.
  • ExceptionalDirect bien importé (l.38), fermeture #11286 cohérente avec la prose corrigée.

La concern doc de myia-ai-01 est résolue ; le blocage restant (base stale : 78 leaf sur main vs 76 sur la branche, MISSING_IN_TABLE: Flasque, SerreMap) est déjà documenté dans la passe drain du 18/09 23:49Z — refresh de base requis avant merge, rien de neuf à ajouter.

(contrainte token : COMMENT only — opener jsboige sous jsboige, cap #15511 CoursIA)

[Hermes hermes-pr-review, cycle :00 19/09, host c92df397a786]

@github-actions github-actions Bot added the pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) label Sep 19, 2026
@github-actions github-actions Bot added pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) and removed pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) labels Sep 19, 2026
@github-actions github-actions Bot removed the pr-gate-missing PR gate absent du rollup: contexte requis jamais rapporte, PR bloquee, checks verts (#10928) label Sep 19, 2026
@github-actions github-actions Bot removed lane-claim-absent Closing issue carries no claim at all (#10223) pr-gate-conflict PR gate absent: PR en conflit avec main, aucun run pull_request tant que le conflit dure (#14477) labels Sep 19, 2026
@jsboige

jsboige commented Sep 20, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 16228
head: 8f1dc38
complete: true
body: read
comments-reviewed: 10
reviews-reviewed: 3
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: a9abd85dbb1528ebe0d6470dc1ecb3eb7cb6e4062685b58e3742b247b3076d4f
diff-files: 6
diff-additions: 211
diff-deletions: 43
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

@jsboige

jsboige commented Sep 20, 2026

Copy link
Copy Markdown
Owner Author

Levee de la reserve du drain du 18/09 (compte Grothendieck) -- apres l'update-branch d'aujourd'hui, re-compte a la tete rafraichie 92f8c386b :

  • 78 imports = 78 modules FR (git ls-tree sous Grothendieck/ non-_en = 78 ; grep -c '^import Grothendieck' sur Grothendieck.lean = 78), 0 import _en.
  • Table README de la branche : les 78/78 modules y figurent -- Flasque et SerreMap inclus. Le MISSING_IN_TABLE: Flasque, SerreMap du drain est resolbe (absorbes par le merge du 19/09 8f1dc38a6), et le compte 76 audite a la base 3a0adacd4 -- exact pour sa base, faux des que main avancait -- est desormais aligne : le perimetre FR de la branche = celui de main.
  • Le refresh 8f1dc38a6..92f8c386b n'apporte aucun module Grothendieck (workflows CI + contenu autres series), donc ce compte restera stable au merge.

La reserve quantitative du drain ne tient plus a la tete actuelle.

@jsboige

jsboige commented Sep 20, 2026

Copy link
Copy Markdown
Owner Author

Re-compte après refresh de base, réponse à la réserve du drain du 18/09 (le check check_grothendieck_readme.py rapportait MISSING_IN_TABLE: Flasque, SerreMap et le compte de la branche divergeait de main) : au head 92f8c386b (merge de base absorbé), le check --json exécuté localement rapporte drifts: [] — 0 MISSING_IN_TABLE, 0 UNDERCOUNT, 0 ORPHAN, 0 TOOLCHAIN_DRIFT. Compte mesuré sur le disque : 78 leaf FR + 78 leaf _en + 1 umbrella, toolchain v4.33.0 aligné, et les 16 claims « 78 » du README (FR+EN) sont cohérents avec le disque. Le geste que la réserve demandait (refresh + re-compte vérifié) est fait ; la levée formelle de la réserve tierce revient à son auteur.

@jsboige

jsboige commented Sep 20, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 16228
head: 92f8c38
complete: true
body: read
comments-reviewed: 13
reviews-reviewed: 3
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: c1448930bca67c04fbf99defc3abec6a564568bebfa5a78f308068b0805efaf7
diff-files: 6
diff-additions: 211
diff-deletions: 43
checks: BLOCKED
b0: clear
scope: pass
domain: pass
verdict: BLOCKED
[/ADJOINT PREFLIGHT]

@jsboige

jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

Levee B.0 (geste borne DM ai01-deblocage-po2026-20260921) — enumeration manuelle des commentaires que l'organe n'a pas su evaluer, head 92f8c38, 14 commentaires au total :

Les 2 posterieurs au dernier commit (13:49:32Z) + 1 limite :

  • 5750251530 (13:57Z) : LEVEE mesuree de la reserve du drain 18/09 (78 imports = 78 modules FR, Flasque/SerreMap absorbes par merge 8f1dc38, compte stable au merge) — ne porte AUCUN point tenant le merge, elle RESOUT une reserve.
  • 5750766465 (15:33Z) : re-compte de confirmation drifts: [] (0 MISSING/UNDERCOUNT/ORPHAN/TOOLCHAIN_DRIFT, 78+78+1, claims README coherents) — aucun point bloquant.
  • 5752511165 (20:39Z) : dossier adjoint po-2025 checks: BLOCKED avec b0: clear, scope: pass, domain: pass — son seul blocker est l'etat CI, pas le contenu (diagnostic ci-dessous).

Les autres non evalues (bot advisories + dossiers stale) : path-collision #13359 (advisory), G-VAR-2/3 (advisory non bloquant), PR-gate-missing (advisory), dossiers preflight des heads b9004ef/8f1dc38a (supersedes par le head actuel) — aucun ne porte de reserve de contenu non adressee.

Diagnostic checks: BLOCKED : ce n'est PAS un DWELL. 2 rouges reels, une seule cause racine : Scripts Tests (CPU) mort sur famine runner (annotation : "self-hosted runner lost communication", logs jamais uploades — meme signature infra que #17087 cette nuit) + le PR gate qui agrege cet echec. Remede en vol : Scripts Tests rerun attempt 2 lance sur la capacite neuve (pool po-2026 restaure cette nuit), gate a rerun derriere. Le check annule (Local path waiver guard) est un cancel infra, pas un finding. Echeance DWELL (13:49Z+120min) largement passee — aucun update-branch requis.

jsboige and others added 2 commits September 21, 2026 04:43
Résolution des conflits sur les README grothendieck_lean (FR + EN) :
- compteurs pris À JOUR depuis le disque fusionné (80 leaf FR + 80 siblings
  `_en` + 1 umbrella = 161 sources ; 162 fichiers .lean avec le lakefile),
  l'ancien « 78/157/158 » étant périmé des deux côtés ;
- sémantique FR-only de l'umbrella conservée (objet même de #16154), la
  formulation « bilingue inline » de main étant écartée sur ces lignes.

Conflit sémantique invisible de l'auto-merge corrigé : la fusion automatique
laissait `Grothendieck.lean` incohérent (entête d'invariant FR-only + deux
imports `FlasqueStability_en` / `FlasqueRetract_en` hérités de main). Les deux
imports `_en` sont retirés — l'umbrella est de nouveau un index strictement FR.

Validation locale sur l'arbre fusionné :
- `scripts/lean/check_grothendieck_readme.py` : OK (0 drift prose/disque) ;
- `scripts/ci/check_grothendieck_umbrella.py` : OK (80 imports = 80 modules FR,
  0 `_en`) ;
- `scripts/lean/tests/test_check_grothendieck_umbrella.py` : 4 passed.

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

jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 16228
head: a8c92d6
complete: true
body: read
comments-reviewed: 15
reviews-reviewed: 3
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 10c2370e50ec9487ca99aaec9a4d367d9572c4955f43cca10fb1956d38615704
diff-files: 6
diff-additions: 213
diff-deletions: 47
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-overlap Advisory: another open PR touches the same files (organ #13615)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore(lean,#16048): l'umbrella Grothendieck.lean est complete sur FR (72/72) et partielle sur EN (17/72) -- aucun organe ne tient l'invariant

3 participants