Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ce364b7
docs: draft ADR-0023 for the one-time editorial refactoring
Reefact Jul 19, 2026
69cddcf
docs: translate ADR-0023 to French
Reefact Jul 19, 2026
09e32fc
docs: add the ADR implementation reference
Reefact Jul 19, 2026
26534af
docs: translate the ADR implementation reference to French
Reefact Jul 19, 2026
8d599a7
docs: record the ADR editorial exception in the index
Reefact Jul 19, 2026
df8a969
docs: separate the Roslyn floor decision from its implementation
Reefact Jul 19, 2026
172fda4
docs: translate ADR-0001's editorial rewrite to French
Reefact Jul 19, 2026
d11214d
docs: separate the tooling floor decision from its implementation
Reefact Jul 19, 2026
47a0f15
docs: translate ADR-0002's editorial rewrite to French
Reefact Jul 19, 2026
fc86f3f
docs: clarify the ADR review decision and its enforcement boundary
Reefact Jul 19, 2026
b79358c
docs: translate ADR-0004's editorial rewrite to French
Reefact Jul 19, 2026
f1c858e
docs: accept and simplify the nullable value-type binder ADR
Reefact Jul 19, 2026
ed51ef0
docs: translate ADR-0008's editorial rewrite to French
Reefact Jul 19, 2026
8f637c1
docs: separate the GenDoc catalog decision from release mechanics
Reefact Jul 19, 2026
a537e38
docs: translate ADR-0010's editorial rewrite to French
Reefact Jul 19, 2026
5ed4c6c
docs: accept and simplify the standalone Dummies package ADR
Reefact Jul 19, 2026
0cbf79e
docs: translate ADR-0011's editorial rewrite to French
Reefact Jul 19, 2026
9cb5480
docs: accept and simplify the distinct-collection ADR
Reefact Jul 19, 2026
e518db1
docs: translate ADR-0013's editorial rewrite to French
Reefact Jul 19, 2026
cab2441
docs: accept and simplify the Any.Combine arity ADR
Reefact Jul 19, 2026
142f04b
docs: translate ADR-0015's editorial rewrite to French
Reefact Jul 19, 2026
055686d
docs: separate the binder catalog decision from its documentation seams
Reefact Jul 19, 2026
cff4d1e
docs: translate ADR-0019's editorial rewrite to French
Reefact Jul 19, 2026
f187fa0
docs: accept and simplify the source-agnostic binder ADR
Reefact Jul 19, 2026
687172d
docs: translate ADR-0021's editorial rewrite to French
Reefact Jul 19, 2026
62b2dd5
docs: separate the .NET Framework floor decision from test mechanics
Reefact Jul 19, 2026
10b5f23
docs: translate ADR-0022's editorial rewrite to French
Reefact Jul 19, 2026
6ef0daf
docs: sync accepted ADR statuses in the index
Reefact Jul 19, 2026
e8110e2
docs: separate the binder-options decision from its API mechanics
Reefact Jul 19, 2026
a360a76
docs: translate ADR-0012's editorial rewrite to French
Reefact Jul 19, 2026
0fa459d
docs: separate the binder-default decision from its implementation
Reefact Jul 19, 2026
7dfb5e9
docs: translate ADR-0017's editorial rewrite to French
Reefact Jul 19, 2026
7d74b82
docs: renumber the ADR editorial-migration record to ADR-0024
claude Jul 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ADR-0001 | Verrouiller le floor Roslyn de l'analyzer
# ADR-0001 | Verrouiller le plancher Roslyn de l'analyseur

🌍 🇬🇧 [English](0001-lock-the-analyzer-roslyn-floor.md) · 🇫🇷 Français (ce fichier)

Expand All @@ -8,186 +8,66 @@

## Contexte

`FirstClassErrors.Analyzers` est un analyzer Roslyn livré **intégré dans le
package NuGet `FirstClassErrors`** (à `analyzers/dotnet/cs/`), de sorte que les
consommateurs qui référencent le package obtiennent automatiquement les
diagnostics `FCExxx`, sans installation supplémentaire.
`FirstClassErrors.Analyzers` est intégré au package NuGet `FirstClassErrors` et chargé par le compilateur de chaque consommateur. La version de Roslyn contre laquelle l'analyseur est compilé devient donc la version minimale du compilateur capable de le charger.

Un analyzer intégré est chargé par **le compilateur hôte de chaque
consommateur** — le Roslyn fourni avec leur SDK .NET ou leur IDE. La version de
`Microsoft.CodeAnalysis.*` contre laquelle l'analyzer est *compilé* devient donc
le Roslyn **minimum** capable de le charger :
Une mise à jour ordinaire de la dépendance Roslyn peut relever silencieusement ce minimum. La CI moderne et l'IDE du mainteneur ne révèlent pas la régression puisqu'ils satisfont déjà le nouveau plancher. Le dépôt a déjà subi cette dérive lorsque l'analyseur a fini par exiger Roslyn 5.6.

* si l'analyzer référence un Roslyn **plus récent** que l'hôte, l'hôte refuse de
le charger et émet **`CS8032`** (et l'analyzer ne fait silencieusement rien) ;
* si l'analyzer lève une exception lors du chargement, l'hôte émet **`AD0001`**.

Une montée de version de routine de la dépendance `Microsoft.CodeAnalysis.*`
élève donc silencieusement le SDK/IDE minimum que chaque consommateur doit
posséder. Cette régression précise s'est produite une fois : l'analyzer a dérivé
jusqu'à exiger Roslyn 5.6. Dependabot propose de telles montées de version
automatiquement, comme n'importe quelle autre mise à jour de dépendance.

Le contrat de chargement est invisible sur les chaînes d'outils modernes — la CI
sur le dernier SDK, ainsi que l'IDE du mainteneur lui-même, satisfont l'un comme
l'autre n'importe quel floor — de sorte qu'il peut régresser sans aucun signal
rouge.

L'hôte le plus ancien que FirstClassErrors prend en charge est le **SDK .NET
8.0.100 / Visual Studio 2022 17.8**, dont le compilateur est **Roslyn 4.8**.

`CS8032` n'est émis que lorsqu'un chargement est *tenté* : un analyzer qui n'est
jamais raccordé à une compilation laisse la build au vert. Et l'analyzer atteint
les consommateurs via un chemin de packaging (`analyzers/dotnet/cs/`) qui peut se
casser indépendamment des références propres de l'analyzer.

`Microsoft.CodeAnalysis.Analyzers` (5.6.0) est un analyzer d'authoring à la
compilation (`PrivateAssets="all"`), et non une référence à l'exécution de
l'assembly livré, de sorte qu'il n'affecte pas le contrat de chargement.
Le plus ancien hôte d'analyseur pris en charge est le SDK .NET 8.0.100 / Visual Studio 2022 17.8, qui embarque Roslyn 4.8. Une garantie complète de compatibilité doit couvrir à la fois les références de l'analyseur et l'artefact empaqueté réellement chargé par les consommateurs.

## Décision

Le floor Roslyn de l'analyzer est fixé à **4.8.0** — le Roslyn de l'hôte pris en
charge le plus ancien — déclaré une seule fois comme `RoslynFloorVersion` dans
`Directory.Build.props` et appliqué par quatre garde-fous indépendants.
Le plancher Roslyn de l'analyseur est fixé à **4.8.0**, la version de Roslyn du plus ancien hôte pris en charge, et protégé par des garde-fous indépendants lors du build, des tests, de l'empaquetage et de la gestion des dépendances.

## Justification

La valeur du floor est dictée par le contexte : 4.8.0 est exactement le Roslyn
livré avec l'hôte le plus ancien que nous prétendons prendre en charge (SDK .NET
8.0.100 / VS 2022 17.8). Un floor plus bas n'apporte rien ; un floor plus haut
abandonne silencieusement des hôtes pris en charge.

Le contrat nécessite plus qu'un simple épinglage de version, car il régresse sans
aucun signal rouge sur les chaînes d'outils modernes. Un épinglage seul
*ressemble* encore à de la maintenance de routine, et une référence trop récente
peut se glisser de trois manières distinctes qu'aucune vérification unique
n'attrape : la *version de référence* peut dériver, l'analyzer livré peut échouer
à se *charger* sur un hôte ancien, et il peut échouer à être *packagé* là où les
consommateurs le cherchent. La décision superpose donc une **défense en
profondeur** — une source unique de vérité et quatre garde-fous, chacun fermant
une brèche que les autres ne peuvent fermer :

* le floor est déclaré **une seule fois**, comme `RoslynFloorVersion` dans
`Directory.Build.props`, de sorte que l'épinglage, le test et le job CI suivent
une valeur unique et ne peuvent jamais diverger ;
* **l'épinglage** compile l'analyzer contre exactement ce Roslyn, fixant le floor
à sa source ;
* **le test unitaire** (`RoslynFloorTests`) relit le floor depuis les métadonnées
de l'assembly et échoue, rapidement et in-process, si un quelconque assembly
`Microsoft.CodeAnalysis*` référencé le dépasse — attrapant la dérive de
*référence* ;
* **le job CI de floor-check** empaquette la bibliothèque et reconstruit
l'exemple contre l'analyzer empaqueté sous le SDK du floor, prouvant que
l'**artefact livré** à la fois se **charge** et est **packagé** correctement sur
le **compilateur pris en charge le plus ancien** — les deux brèches que le test
unitaire ne peut atteindre ;
* **l'ignore Dependabot** empêche une PR automatisée de jamais proposer la montée
de version, de sorte que relever le floor reste un acte conscient plutôt qu'une
mise à jour entérinée sans examen.

Deux des garde-fous échouent **bruyamment** (le test unitaire et le job CI) ;
l'épinglage et l'ignore Dependabot fonctionnent silencieusement par construction.
Ensemble, ils satisfont l'exigence posée par le contexte : un garde-fou qui
échoue sur l'hôte le **plus ancien**, sur l'**artefact exact que nous livrons**,
avant qu'un consommateur ne voie jamais `CS8032`. Le compromis accepté est
l'entretien d'un job CI délibérément complexe et d'un projet `tools/floor-check/`
hors-solution ; les mécanismes de ce job — la séparation en deux SDK, la preuve
de chargement et les pièges NuGet qu'il ferme — sont documentés dans la
[référence du workflow `analyzers`](../workflows/analyzers.fr.md), et l'épinglage
et les métadonnées résident dans `FirstClassErrors.Analyzers.csproj`.
Le plancher découle directement de la promesse de compatibilité : une version supérieure exclurait silencieusement un hôte pris en charge, tandis qu'une version inférieure n'ajouterait aucun environnement supporté.

## Alternatives envisagées
Un simple épinglage de version ne suffit pas, car la dérive des références, le chargement de l'analyseur et son emplacement dans le package sont des modes de panne distincts. Des garde-fous indépendants apportent une défense en profondeur et vérifient l'artefact réellement livré sur le plus ancien compilateur pris en charge, pas seulement dans un environnement de développement moderne.

### Suivre le Roslyn courant et laisser passer les montées de version de dépendances (statu quo)
Le coût de maintenance supplémentaire est justifié, car les échecs de chargement de l'analyseur restent autrement invisibles au mainteneur et n'apparaissent chez les consommateurs qu'après publication.

Envisagée parce que c'est le comportement par défaut, sans effort : les montées
de version de Roslyn arrivent comme des mises à jour de dépendances de routine,
et rien dans la chaîne d'outils ne s'y oppose.
La réalisation technique actuelle et la procédure de relèvement du plancher sont documentées dans la [référence d'implémentation des ADR](../specifications/adr-implementation-reference.fr.md#plancher-de-compatibilité-de-lanalyseur) et la [référence du workflow `analyzers`](../workflows/analyzers.fr.md).

Rejetée parce que chaque montée de version élève silencieusement le SDK/IDE
minimum que chaque consommateur doit posséder — la dérive vers Roslyn 5.6 s'est
produite exactement de cette manière, sans aucun signal rouge nulle part.
## Alternatives envisagées

### Épingler la version de Roslyn, sans garde-fous supplémentaires
### Suivre la version courante de Roslyn

Envisagée comme le correctif minimal : un épinglage d'une ligne arrête la dérive.
Envisagé car il s'agit du chemin normal de maintenance des dépendances. Rejeté parce que chaque mise à jour relève silencieusement la version minimale du SDK et de l'IDE exigée des consommateurs.

Rejetée parce qu'un simple épinglage *ressemble* encore à de la maintenance de
routine — Dependabot continue de proposer la montée de version, et en accepter
une ne fait rien échouer : aucun test ne relit le floor, et aucune build ne
s'exécute sur l'hôte le plus ancien. La régression reviendrait avec la prochaine
mise à jour bien intentionnée.
### Épingler la version sans garde-fous supplémentaires

### S'appuyer sur le seul test unitaire (pas de job CI de floor-check)
Envisagé comme correction minimale. Rejeté parce que cela ne prouve ni que l'analyseur empaqueté se charge sur l'hôte plancher, ni qu'une future mise à jour bien intentionnée ne réintroduira pas la régression.

Envisagée parce que le test est rapide, in-process, et s'exécute dans le
`dotnet test` ordinaire.
### S'appuyer uniquement sur un test des références d'assembly

Rejetée parce qu'elle n'attrape que la dérive de version de *référence*. Elle ne
peut pas prouver que l'artefact livré se **charge** réellement sur l'hôte pris en
charge le plus ancien, ni que l'analyzer est réellement **packagé** à
`analyzers/dotnet/cs/` — deux choses qui peuvent se casser alors que chaque
version de référence reste au floor.
Envisagé car il est rapide et déterministe. Rejeté parce qu'il ne peut prouver ni que l'analyseur est empaqueté à l'emplacement attendu, ni que l'artefact livré se charge sur le plus ancien compilateur.

## Conséquences

### Positives

* Le contrat de chargement ne peut pas régresser silencieusement : une référence
Roslyn trop récente fait échouer le test unitaire (rapide) **et** le job de
floor-check (authentique), et un chemin de packaging cassé fait échouer le job
de floor-check.
* Le job de floor-check teste l'*artefact livré* sur l'*hôte pris en charge le
plus ancien*, et non un substitut.
* Le floor est une décision d'une seule ligne, auto-documentée
(`RoslynFloorVersion`).
* Le compilateur minimal de l'analyseur ne peut plus dériver au gré de la maintenance courante des dépendances.
* La promesse de compatibilité est vérifiée sur l'artefact empaqueté et sur le plus ancien hôte pris en charge.
* Un relèvement du plancher reste une décision architecturale explicite.

### Négatives

* Deux garde-fous supplémentaires à maintenir au vert, et un projet
`tools/floor-check/` hors-solution avec une configuration NuGet
intentionnellement complexe (documentée dans la [référence du workflow
`analyzers`](../workflows/analyzers.fr.md)).
* Le job de floor-check télécharge le SDK 8.0.100 à chaque exécution (~quelques
secondes).
* Relever le floor est un acte délibéré et en plusieurs étapes (à dessein).
* Plusieurs garde-fous complémentaires doivent être maintenus.
* Relever le plancher exige des modifications coordonnées du build, des tests, de l'empaquetage et de la documentation.

### Risques

* La configuration NuGet du floor-check paraît sur-conçue à un lecteur qui ne
connaît pas les pièges qu'elle ferme ; une future « simplification » en
réintroduirait un comme un bug silencieux. Atténuation : chaque subtilité est
consignée dans la [référence du workflow `analyzers`](../workflows/analyzers.fr.md)
et dans les commentaires YAML du workflow lui-même.
* Lorsque le floor est relevé, le SDK du floor épinglé dans `analyzers.yml` et
dans `tools/floor-check/global.json` doit être déplacé à la main ; les oublier
laisse le job valider l'ancien floor. Atténuation : la procédure de relèvement
ci-dessous les liste explicitement.
* Un futur mainteneur pourrait supprimer un garde-fou dont l'utilité n'est pas évidente. Mesure : les mécanismes sont documentés dans les références d'implémentation et de workflow.
* Un garde-fou pourrait continuer à valider un ancien plancher après un changement volontaire. Mesure : tout changement de plancher doit remplacer cet ADR et suivre la procédure documentée.

## Actions de suivi

* Aucune dans l'immédiat : les quatre garde-fous (épinglage, `RoslynFloorTests`,
le job de floor-check `analyzers.yml`, l'ignore Dependabot) ont été livrés avec
cette décision.
* Si le floor est un jour relevé :
1. Monter `<RoslynFloorVersion>` dans `Directory.Build.props`.
2. Mettre à jour le SDK du floor dans `analyzers.yml` (`dotnet-version` et le
`tools/floor-check/global.json` imbriqué) vers le SDK dont le Roslyn
correspond au nouveau floor.
3. Mettre à jour la note d'exigence de compilateur du README /
`doc/handwritten/for-users/README.fr.md`.
4. Remplacer cet ADR (nouveau floor, nouveau SDK/IDE minimum).

L'épinglage, le test unitaire et l'ignore Dependabot ne nécessitent aucun
changement — ils suivent tous `$(RoslynFloorVersion)` ou les identifiants de
package.
* Aucune action immédiate.
* Remplacer cet ADR lorsque le plancher Roslyn pris en charge change.

## Références

* Façonné par #69 (verrouillage initial) et #74 / #75 / #77 (durcissement du
floor-check).
* [ADR-0002](0002-floor-the-tooling-runtime.fr.md) — le floor du runtime
d'outillage, le pendant à l'exécution de cette décision à la compilation.
* [référence du workflow `analyzers`](../workflows/analyzers.fr.md) — le job de
floor-check, structurellement.
* [Référence d'implémentation des ADR — Plancher de compatibilité de l'analyseur](../specifications/adr-implementation-reference.fr.md#plancher-de-compatibilité-de-lanalyseur)
* [Référence du workflow `analyzers`](../workflows/analyzers.fr.md)
* [ADR-0002](0002-floor-the-tooling-runtime.fr.md) — la décision équivalente pour le runtime.
* [ADR-0024](0024-allow-a-one-time-editorial-refactoring-of-accepted-adrs.fr.md) — autorise cette extraction éditoriale.
Loading