0.0.5-alpha.5.fix.1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/005-V0_0_5_RECONCILIATION_PLAN.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Plan 0.0.5 — réconciliation réelle avec KSP et sasedev-games
|
||||
|
||||
@@ -84,11 +84,13 @@ Cette tranche ne commence pas l'audit Rust ni le profil Tauri.
|
||||
|
||||
Extraire le noyau réellement commun de `audit_rust_export_completeness.py`, l'aligner avec `510-RUST_CARGO.md`, documenter son caractère facultatif et ses limites, et ajouter des tests positifs/négatifs.
|
||||
|
||||
La réconciliation a révélé que le script historique ne découvrait que `crates/*/Cargo.toml` : il couvrait les `22` crates KSP mais aucune des `23` crates Games imbriquées sous des sous-familles. La variante PGR doit donc corriger la découverte récursive avant toute généralisation. Elle doit également abandonner les sous-règles historiques de tests séparés et la duplication de résolution de noms déjà possédée par le compilateur.
|
||||
La réconciliation a révélé que le script historique ne découvrait que `crates/*/Cargo.toml` : il couvrait les `22` packages KSP mais aucun des `23` packages Games imbriqués sous des sous-familles. La variante PGR corrige donc la découverte récursive et distingue aussi les cibles `lib`/`bin` d'un même package pour ne pas confondre plusieurs crates Rust compilées séparément.
|
||||
|
||||
Mesure de référence avec le scope PGR retenu : `KSP = 0 candidate(s) / 22 crates`, `Games = 2 candidate(s) / 23 crates`. Les deux signaux Games sont une observation de réconciliation, pas une non-conformité rétroactive.
|
||||
La première livraison `alpha.5` a ensuite révélé un second défaut de scope pendant la revue opérateur : elle ne détectait que les chemins internes longs tels que `crate::module::Item`, alors que le contrat attendu impose `crate::Item` pour **toute référence intra-crate à un item partagé**, y compris un nom nu dans son module propriétaire. La gate mécanique était verte mais l'acceptation fonctionnelle est donc `FAIL`; `alpha.5.fix.1` corrige ce blind spot sans commencer Tauri.
|
||||
|
||||
Cette tranche ne réimporte pas `audit_rust_general_rules.py` en bloc. Toute règle déjà possédée par Rustfmt, Clippy, le compilateur ou les audits PGR existants reste chez son owner actuel.
|
||||
Mesure `alpha.5.fix.1` en `--report-only --summary-only` : KSP `0.3.16` = `1525` lignes candidates `RUST-IMPORT-201` sur `22` packages ; Games `0.3.5` = `181` lignes candidates sur `23` packages (`2 RUST-API-201`, `179 RUST-IMPORT-201`). Ces nombres forment un inventaire d'adoption future, pas une non-conformité rétroactive des baselines.
|
||||
|
||||
Cette tranche ne réimporte pas `audit_rust_general_rules.py` en bloc et ne réintroduit pas le diagnostic historique de résolution `crate::X` déjà possédé par le compilateur. Toute autre règle déjà possédée par Rustfmt, Clippy, le compilateur ou les audits PGR existants reste chez son owner actuel.
|
||||
|
||||
### alpha.6 — premier profil framework : Tauri
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/rules/510-RUST_CARGO.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Profil Rust / Cargo
|
||||
|
||||
@@ -90,9 +90,11 @@ Tout élément `pub` ou `pub(crate)` SHOULD posséder une rustdoc utile au point
|
||||
|
||||
Une crate réutilisable SHOULD exposer son API durable depuis son crate-root par des réexports explicites. Les modules d'implémentation SHOULD rester privés ; `pub mod` ne doit pas être utilisé uniquement pour éviter de concevoir une façade stable.
|
||||
|
||||
Un élément partagé à l'échelle de sa propre crate SHOULD être consommable via `crate::Item` après réexport approprié. Les autres crates consomment l'API publique du crate propriétaire plutôt que ses chemins internes.
|
||||
Lorsqu'un projet adopte le **contrat strict de façade crate-root**, un élément `pub` d'un module fichier MUST être réexporté explicitement au crate-root. Un élément `pub(crate)` consommé hors de son module MUST de même posséder un réexport `pub(crate)` au crate-root. Un helper réellement local SHOULD rester privé plutôt qu'élargir artificiellement sa visibilité.
|
||||
|
||||
Les glob imports SHOULD être évités. Un alias de réexport ne doit pas servir à masquer durablement une collision de noms dans l'API ; lorsqu'un nom fait partie du contrat public, le propriétaire SHOULD choisir un nom canonique non ambigu.
|
||||
Dès qu'un item possède cette identité crate-root, toute référence dans la même crate MUST utiliser `crate::Item`, y compris depuis son module de déclaration et depuis ses tests unitaires attachés. Les formes `Item`, `self::Item`, `super::Item`, `module::Item` et `crate::module::Item` ne sont pas des chemins de consommation canoniques pour cet item partagé. Un élément strictement privé reste local au module ; un test unitaire attaché peut alors utiliser `super::PrivateItem`.
|
||||
|
||||
Les autres crates consomment l'API publique du crate propriétaire via `owner_crate::Item` plutôt que ses chemins internes. Les glob imports SHOULD être évités. Un alias de réexport ne doit pas servir à masquer durablement une collision de noms dans l'API ; lorsqu'un nom fait partie du contrat public, le propriétaire SHOULD choisir un nom canonique non ambigu.
|
||||
|
||||
PGR ne généralise pas l'interdiction KSP plus stricte de tous les `use` non-traits : cette convention appartient à un profil ou projet plus spécifique tant qu'elle n'est pas nécessaire au contrat Rust général.
|
||||
|
||||
@@ -194,6 +196,6 @@ Un éventuel wrapper d'orchestration MAY appeler plusieurs audits, mais chaque a
|
||||
|
||||
Les deux audits de style disponibles sont documentés dans [`../validation/002-RUST_STYLE_AUDITS.md`](../validation/002-RUST_STYLE_AUDITS.md). Ils restent optionnels et prennent un corpus Rust explicitement sélectionné.
|
||||
|
||||
[`../validation/003-RUST_EXPORT_COMPLETENESS.md`](../validation/003-RUST_EXPORT_COMPLETENESS.md) documente séparément un audit facultatif de façade crate-root. Lorsqu'un projet choisit ce contrat strict, les éléments `pub` des modules fichiers et les éléments `pub(crate)` clairement partagés hors de leur module SHOULD être réexportés explicitement au crate-root ; lorsqu'un tel réexport existe, les chemins internes SHOULD employer `crate::Item` plutôt que `crate::module::Item`.
|
||||
[`../validation/003-RUST_EXPORT_COMPLETENESS.md`](../validation/003-RUST_EXPORT_COMPLETENESS.md) documente séparément l'audit facultatif qui matérialise ce contrat strict. `RUST-API-201` vérifie la présence de la façade pour les items partagés ; `RUST-IMPORT-201` vérifie que les références intra-crate détectées passent réellement par `crate::Item`, y compris dans le module propriétaire, et pas seulement qu'un chemin interne long a été évité.
|
||||
|
||||
Cet audit de façade ne rend pas la règle obligatoire pour tous les projets Rust et ne remplace pas le compilateur. Le dépôt PGR lui-même ne contient pas de workspace Rust sur lequel une telle gate fournirait une preuve runtime ou Cargo réelle.
|
||||
Cet audit ne rend pas le contrat strict obligatoire pour tous les projets Rust et ne remplace pas le compilateur. Il contrôle au contraire une convention architecturale que `rustc` et Clippy ne possèdent pas. Le dépôt PGR lui-même ne contient pas de workspace Rust sur lequel une telle gate fournirait une preuve runtime ou Cargo réelle.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/studies/001-KSP_GAMES_RECONCILIATION.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Étude de réconciliation PGR / KSP / sasedev-games
|
||||
|
||||
@@ -137,7 +137,9 @@ Décision : classer ce contrôle `COMMON`, mais ne pas copier le script tel quel
|
||||
|
||||
La relecture du script historique révèle une limite importante : sa découverte `crates/*/Cargo.toml` couvre les `22` crates KSP placées directement sous `crates/`, mais aucune des `23` crates Games imbriquées sous `crates/apps`, `crates/common`, `crates/engines`, etc. Le code des deux scripts est bien commun, mais le résultat historique Games `0 candidate(s)` n'était pas une preuve d'audit des crates réelles.
|
||||
|
||||
La variante PGR corrige la découverte récursive et réduit le scope aux deux propriétés effectivement possédées par `510-RUST_CARGO.md` : complétude de la façade crate-root et canonicalisation d'un chemin interne lorsqu'un réexport explicite existe. Avec cette variante, KSP donne `0 candidate(s)` sur `22` crates et Games `2 candidate(s)` sur `23` crates. Ces deux signaux Games ne sont pas des non-conformités rétroactives ; ils deviennent des points de décision lors d'une future adoption PGR.
|
||||
La variante PGR corrige d'abord la découverte récursive. La revue opérateur de `alpha.5` montre ensuite que limiter la canonicalisation à `crate::module::Item` est insuffisant : les corpus contiennent de nombreuses références nues à des items pourtant réexportés, notamment dans leur module propriétaire, et ni `rustc` ni Clippy ne possèdent la convention « référence partagée = `crate::Item` partout dans la crate ». `alpha.5` est donc conservé `FAIL` et `alpha.5.fix.1` étend `RUST-IMPORT-201` à ce contrat réel.
|
||||
|
||||
La mesure corrigée, avec découverte récursive et séparation des cibles Cargo, donne `1525` lignes candidates `RUST-IMPORT-201` dans KSP sur `22` packages et `181` lignes candidates dans Games sur `23` packages (`2 RUST-API-201`, `179 RUST-IMPORT-201`). Ces volumes ne sont pas interprétés comme des défauts rétroactifs : ils montrent précisément pourquoi une adoption PGR d'un projet existant doit commencer en `--report-only`, puis migrer progressivement la convention avant d'en faire une gate bloquante.
|
||||
|
||||
Le grand `audit_rust_general_rules.py` des deux corpus reste `DEFER` comme source d'extraction, pas comme script à importer. Il mélange plusieurs responsabilités : headers, rustdoc, imports, structure de façade, blancs, constantes et règles locales ; Games y ajoute une exception FFI Android étroite. PGR doit continuer à extraire des audits monotâches seulement lorsqu'une propriété commune apporte une preuve non redondante.
|
||||
|
||||
|
||||
@@ -1,51 +1,111 @@
|
||||
<!-- file: docs/validation/003-RUST_EXPORT_COMPLETENESS.md -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Audit facultatif de façade Rust et export completeness
|
||||
# Audit facultatif de façade Rust et canonicalisation intra-crate
|
||||
|
||||
## Responsabilité
|
||||
|
||||
`scripts/audit_rust_export_completeness.py` contrôle un contrat Rust optionnel plus strict que les garanties du compilateur : les éléments publics durables d'un module fichier doivent être exposés par une façade explicite au crate-root, et le code de la même crate doit employer cette façade lorsqu'un réexport correspondant existe.
|
||||
`scripts/audit_rust_export_completeness.py` contrôle un contrat Rust optionnel plus strict que les garanties du compilateur et de Clippy : une crate qui adopte cette convention possède une façade crate-root explicite pour ses items partagés, et toute consommation intra-crate d'un item possédant cette identité canonique passe par `crate::Item`.
|
||||
|
||||
Le propriétaire normatif reste [`../rules/510-RUST_CARGO.md`](../rules/510-RUST_CARGO.md). Le script ne définit pas une architecture à lui seul et ne doit être adopté que par un projet qui choisit ce contrat de façade.
|
||||
Le propriétaire normatif reste [`../rules/510-RUST_CARGO.md`](../rules/510-RUST_CARGO.md). Le script ne définit pas une architecture à lui seul ; il matérialise uniquement le contrat strict lorsqu'un projet choisit de l'adopter.
|
||||
|
||||
L'audit émet seulement deux familles de diagnostics :
|
||||
L'audit émet deux familles de diagnostics :
|
||||
|
||||
```text
|
||||
RUST-API-201
|
||||
élément `pub`, ou élément `pub(crate)` clairement consommé hors de son module fichier,
|
||||
sans réexport explicite correspondant au crate-root
|
||||
item `pub` d'un module fichier sans réexport explicite au crate-root,
|
||||
ou item `pub(crate)` clairement consommé hors de son module sans réexport crate-root
|
||||
|
||||
RUST-IMPORT-201
|
||||
chemin interne long `crate::module::Item` alors que le crate-root expose déjà `crate::Item`
|
||||
référence intra-crate non canonique à un item possédant une identité crate-root ;
|
||||
la forme attendue est `crate::Item`
|
||||
```
|
||||
|
||||
Il ne vérifie pas les règles générales de style, les lignes vides, l'ordre des constantes, la rustdoc, les lints Cargo/Clippy, la sûreté FFI ou le contenu métier.
|
||||
`RUST-IMPORT-201` ne se limite donc pas à `crate::module::Item`. Il couvre notamment :
|
||||
|
||||
```text
|
||||
Item
|
||||
self::Item
|
||||
super::Item
|
||||
module::Item
|
||||
crate::module::Item
|
||||
```
|
||||
|
||||
lorsque ces formes désignent un item partagé déjà exposé comme `crate::Item`.
|
||||
|
||||
La règle s'applique également **dans le module qui déclare l'item**. Par exemple :
|
||||
|
||||
```rust
|
||||
pub struct Runtime;
|
||||
|
||||
impl Runtime {
|
||||
pub fn new() -> Runtime {
|
||||
return Runtime;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
n'est pas canonique après réexport de `Runtime`. Le contrat strict attend :
|
||||
|
||||
```rust
|
||||
pub struct Runtime;
|
||||
|
||||
impl crate::Runtime {
|
||||
pub fn new() -> crate::Runtime {
|
||||
return crate::Runtime;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Le même principe vaut pour une fonction partagée appelée depuis son module propriétaire : `crate::build()` est canonique, `build()` ne l'est pas.
|
||||
|
||||
Les lignes de déclaration de l'item et les lignes de réexport qui construisent la façade sont naturellement exemptées. Un item strictement privé n'appartient pas à ce contrat ; dans un test unitaire attaché à son module parent, `super::PrivateItem` reste une forme locale légitime.
|
||||
|
||||
## Pourquoi Cargo/Clippy ne suffisent pas
|
||||
|
||||
Le compilateur vérifie la résolution et la visibilité des noms ; il ne possède pas la convention « tout accès partagé passe par `crate::Item` ». Clippy peut signaler certains imports ou réexports inutilisés, mais une seule consommation correcte de `crate::Item` peut suffire à rendre le réexport utilisé tandis que d'autres références continuent d'employer un nom nu ou un chemin interne.
|
||||
|
||||
L'audit fournit donc une preuve distincte : **uniformité de la façade et des chemins intra-crate**, pas simple compilabilité.
|
||||
|
||||
## Cibles Cargo et graphes de modules
|
||||
|
||||
La `version: 2` ne confond plus automatiquement tous les fichiers d'un package Cargo dans une seule crate. Un package peut contenir simultanément une bibliothèque `src/lib.rs` et un binaire `src/main.rs` ; ces deux cibles sont compilées comme des crates distinctes et `crate::Item` n'y désigne pas la même racine.
|
||||
|
||||
L'audit découvre les packages récursivement puis traite séparément les cibles standard/explicites `lib` et `bin`. Pour chaque cible, il suit les modules fichiers déclarés par `mod name;` et les modules `#[path = "..."]`, ce qui couvre notamment les `unit_tests/` attachés utilisés dans le corpus KSP/Games sans englober les tests d'intégration Cargo sous `tests/`, qui sont des crates externes.
|
||||
|
||||
Cette distinction évite de considérer à tort `owner_crate::Item` utilisé dans un binaire comme une violation de la bibliothèque du même package.
|
||||
|
||||
## Provenance et correction du corpus
|
||||
|
||||
KSP `0.3.16` et Games `0.3.5` contiennent un `audit_rust_export_completeness.py` dont le corps est identique à l'exception de sa révision de fichier. Cette convergence justifie l'extraction du concept, mais pas une copie littérale.
|
||||
KSP `0.3.16` et Games `0.3.5` contiennent un `audit_rust_export_completeness.py` historiquement identique à l'exception de sa révision. Cette convergence justifie l'extraction du concept, mais pas une copie littérale.
|
||||
|
||||
Le script historique découvre uniquement `crates/*/Cargo.toml`. Cette hypothèse couvre les `22` crates KSP situées directement sous `crates/`, mais elle ne couvre aucune des `23` crates Games organisées sous des sous-familles telles que `crates/apps/`, `crates/common/` ou `crates/engines/`. Un résultat historique `0 candidate(s)` dans Games ne constitue donc pas une preuve que ses crates avaient réellement été inspectées par cet audit.
|
||||
Deux limites historiques ont été identifiées :
|
||||
|
||||
La variante PGR corrige ce point en découvrant récursivement les packages Cargo possédant `src/lib.rs` ou `src/main.rs`, tout en ignorant les arbres générés usuels. Elle gère également correctement un module fichier `mod.rs` et les réexports explicites simples, groupés ou aliasés.
|
||||
1. la découverte `crates/*/Cargo.toml` couvrait les `22` packages KSP directement sous `crates/`, mais aucune des `23` crates Games imbriquées sous `crates/apps/`, `crates/common/`, `crates/engines/`, etc. ;
|
||||
2. la canonicalisation détectait surtout `crate::module::Item` et quelques cas particuliers de tests, mais pas les références ordinaires par nom nu dans les modules de production, y compris le module propriétaire.
|
||||
|
||||
La réconciliation générateur réalisée pendant `0.0.5-alpha.5` donne avec la nouvelle découverte :
|
||||
La première version PGR de `alpha.5` corrigeait seulement la découverte récursive et le chemin interne long. La revue opérateur après sa gate a explicitement révélé la seconde lacune ; `alpha.5` est donc conservé `FAIL` et `alpha.5.fix.1` étend `RUST-IMPORT-201` au contrat réellement attendu.
|
||||
|
||||
## Mesure de réconciliation après le fix
|
||||
|
||||
Avec la `version: 2`, en mode `--report-only --summary-only`, les baselines autoritaires de la réconciliation donnent :
|
||||
|
||||
```text
|
||||
KSP 0.3.16 22 crate(s) 0 candidate(s)
|
||||
Games 0.3.5 23 crate(s) 2 candidate(s)
|
||||
KSP 0.3.16
|
||||
22 package(s)
|
||||
1525 candidate(s)
|
||||
RUST-IMPORT-201: 1525
|
||||
|
||||
Games 0.3.5
|
||||
23 package(s)
|
||||
181 candidate(s)
|
||||
RUST-API-201: 2
|
||||
RUST-IMPORT-201: 179
|
||||
```
|
||||
|
||||
Les deux candidats Games sont des constantes `pub(crate)` du smoke WebTransport navigateur consommées depuis d'autres modules sans façade crate-root. Games n'étant pas encore gouverné par PGR, ces signaux ne sont pas qualifiés de défauts rétroactifs ; ils montrent simplement ce qu'une adoption future de ce contrat devrait décider ou corriger.
|
||||
Ces nombres représentent des **lignes candidates**, pas des déclarations distinctes. Ils sont beaucoup plus élevés que la première mesure `0 / 2` parce que le contrat corrige précisément le blind spot signalé : les références nues déjà répandues dans les modules propriétaires et consumers deviennent enfin visibles.
|
||||
|
||||
## Ce qui n'est pas repris du script historique
|
||||
|
||||
PGR n'importe pas les diagnostics historiques liés aux tests unitaires séparés (`super::...`, références non qualifiées) : leur validité dépend du layout et du contrat local des modules de test, et la baseline Games ne prouve pas une convergence opérationnelle sur ce point.
|
||||
|
||||
PGR n'importe pas non plus le contrôle d'un `crate::Symbol` non résolu. Le compilateur Rust est déjà propriétaire de la résolution de noms ; dupliquer cette erreur dans un audit Python n'apporte pas une preuve supplémentaire proportionnée.
|
||||
|
||||
L'audit PGR reste donc monotâche : façade crate-root et canonicalisation des chemins pour les seuls symboles qu'il sait relier explicitement.
|
||||
KSP et Games n'étant pas encore gouvernés par cette version de PGR, ces résultats ne sont pas qualifiés de défauts rétroactifs et ne déclenchent aucune migration dans `0.0.5`. Ils constituent un inventaire d'adoption future. Pour un projet existant, l'usage initial en `--report-only` est donc particulièrement important.
|
||||
|
||||
## Adoption
|
||||
|
||||
@@ -64,20 +124,22 @@ Commande canonique :
|
||||
python3 -B scripts/audit_rust_export_completeness.py --root .
|
||||
```
|
||||
|
||||
Le code de sortie est `0` lorsque le corpus est propre, `1` lorsqu'au moins un candidat est trouvé et `2` lorsque la racine est invalide, illisible ou ne contient aucune crate Rust détectable. `--report-only` permet une phase d'inventaire sans bloquer la gate ; `--summary-only` réduit la sortie aux comptes.
|
||||
Le code de sortie est `0` lorsque le corpus est propre, `1` lorsqu'au moins un candidat est trouvé et `2` lorsque la racine est invalide, illisible ou ne contient aucun package Rust détectable. `--report-only` permet un inventaire sans bloquer la gate ; `--summary-only` réduit la sortie aux comptes.
|
||||
|
||||
Une adoption progressive peut donc commencer par :
|
||||
Une adoption progressive d'un projet existant devrait commencer par :
|
||||
|
||||
```bash
|
||||
python3 -B scripts/audit_rust_export_completeness.py --root . --report-only
|
||||
python3 -B scripts/audit_rust_export_completeness.py --root . --report-only --summary-only
|
||||
```
|
||||
|
||||
puis devenir bloquante une fois les exceptions ou écarts locaux explicitement résolus.
|
||||
puis inventorier/corriger les familles d'écarts avant de rendre l'audit bloquant. Une nouvelle crate créée sous le contrat peut au contraire l'activer immédiatement.
|
||||
|
||||
## Limites
|
||||
|
||||
L'analyse est lexicale et non un parseur Rust complet. Elle vise les déclarations `pub`/`pub(crate)` au niveau racine de modules fichiers et les réexports explicites du crate-root. Les macros générant des items, attributs élaborés, modules inline complexes, `#[path]` non standard et formes de réexport imbriquées au-delà du contrat testé peuvent nécessiter une revue humaine ou les outils Rust du projet.
|
||||
L'analyse reste lexicale et ne remplace pas un parseur Rust complet. Elle vise les déclarations module-level `pub`/`pub(crate)`, les réexports explicites et les références dans le graphe de modules d'une cible. Les macros générant des items, modules inline complexes, `include!`, formes de `#[path]` atypiques et réexports élaborés peuvent nécessiter une revue humaine.
|
||||
|
||||
Un élément `pub(crate)` n'est exigé à la façade que lorsqu'une consommation externe au fichier est clairement détectée par un chemin `crate::module::Item` ou `crate::Item`. L'absence de diagnostic ne prouve donc pas toute la sémantique de visibilité de la crate.
|
||||
Pour réduire les faux positifs, une fonction partagée est reconnue comme référence lorsqu'elle apparaît sous une forme d'appel directe ; l'usage d'une fonction comme valeur de premier ordre peut donc échapper à cette version. Les chemins explicitement qualifiés par une crate externe et les appels de méthodes `.name()` ne sont pas assimilés à un item local de même nom.
|
||||
|
||||
L'audit ne remplace ni `cargo check`, ni Clippy, ni rustdoc. Il complète uniquement une convention architecturale explicitement choisie.
|
||||
Un item `pub(crate)` qui n'est pas clairement consommé hors de son module n'est pas forcé au crate-root par `RUST-API-201`; sa visibilité peut nécessiter une revue séparée. Dès qu'un réexport crate-root existe, ses références détectées sont toutefois soumises à `RUST-IMPORT-201`, y compris dans son module de déclaration.
|
||||
|
||||
L'audit ne remplace ni `cargo check`, ni Clippy, ni rustdoc. Il complète ces outils avec une convention architecturale qu'ils ne possèdent pas.
|
||||
|
||||
Reference in New Issue
Block a user