Files
pgr/docs/skeletons/002-RUST_CARGO_WORKSPACE.md

14 KiB

Skeleton — Rust/Cargo workspace

Objectif

Cette specification décrit la specialization Rust/Cargo d'un projet gouverné par PGR lorsque plusieurs packages Rust partagent réellement une même unité de release, une politique Cargo commune ou une validation de workspace commune.

Elle se compose avec 001-PROJECT_GOVERNANCE_FOUNDATION.md, sélectionne les profils ../rules/500-LANGUAGES.md et ../rules/510-RUST_CARGO.md, puis utilise les templates et guides Rust/Cargo déjà présents dans PGR. Le contrat transversal des skeletons reste possédé par ../rules/220-SKELETONS.md.

Cette specification ne transforme pas PGR en générateur Cargo et ne crée aucune dépendance build ou runtime vers le dépôt PGR après instanciation.

Applicabilité et composition

Appliquer ce skeleton lorsqu'un projet utilise Rust avec Cargo et qu'un workspace représente réellement son unité de gouvernance ou de release.

La composition normale est :

001-PROJECT_GOVERNANCE_FOUNDATION
    ↓
500-LANGUAGES
    ↓
510-RUST_CARGO
    ↓
002-RUST_CARGO_WORKSPACE

Un dépôt contenant plusieurs unités de release indépendantes ne doit pas être forcé dans un workspace à version globale fictive. Un framework, une plateforme, WASM, Android, Tauri, une FFI ou un autre scope plus spécifique peut ajouter ses propres règles sans modifier le contrat Rust/Cargo général.

Owners, guides et artefacts sélectionnés

Les responsabilités générales de version, workflow, documentation et validation sont déjà couvertes par la fondation 001. La présente specialization ajoute :

docs/rules/500-LANGUAGES.md
    contrat commun langage/écosystème

docs/rules/510-RUST_CARGO.md
    workspace, manifests, dépendances, lints, safety, formatage et validation Cargo

docs/templates/001-RUST_CARGO_TOOLING.md
    adaptation de rustfmt.toml, clippy.toml et .cargo/config.toml

docs/templates/002-CARGO_MANIFESTS.md
    adaptation du manifest workspace et du manifest membre

Les cinq artefacts techniques copiables sélectionnés sont :

templates/rust-cargo/rustfmt.toml
templates/rust-cargo/clippy.toml
templates/rust-cargo/.cargo/config.toml
templates/rust-cargo/Cargo.toml
templates/rust-cargo/crates/project-core-lib/Cargo.toml

../validation/002-RUST_STYLE_AUDITS.md et ../validation/003-RUST_EXPORT_COMPLETENESS.md sont seulement des options supplémentaires. Les scripts Rust PGR ne sont copiés que si le projet choisit explicitement les conventions correspondantes. Le helper _rust_audit_common.py peut être partagé entre ces audits.

Décisions destinataire avant copie

Avant de considérer la specialization comme instanciée, résoudre explicitement au minimum :

  1. le release unit gouverné et la relation entre son VERSION et [workspace.package].version ;
  2. le nom court/abréviation canonique du projet, la liste réelle des packages membres, leurs responsabilités, rôles et chemins, puis la conformité de leurs noms au contrat de 510-RUST_CARGO.md ;
  3. l'édition Rust 2024, le resolver Cargo et la toolchain stable compatible, ou l'exception externe explicitement documentée ;
  4. la politique de publication et les métadonnées réelles communes (license, repository, authors) lorsqu'elles existent ;
  5. les dépendances réellement partagées, leurs contraintes de version et les features qui doivent rester locales à chaque membre ;
  6. la politique de versionnement de Cargo.lock adaptée au type de produit ;
  7. les niveaux de lints hérités, les éventuelles exceptions locales et tout besoin réel d'unsafe dans un scope étroit ;
  8. les paramètres rustfmt.toml et clippy.toml à conserver ou adapter ;
  9. l'emplacement des artefacts Cargo et l'identifiant unique utilisé dans .cargo/config.toml si cette politique externe au dépôt est retenue ;
  10. les frontières -api / -lib réellement justifiées, les packages exécutables distincts de leurs bibliothèques et toute exception framework à cette séparation ;
  11. l'ownership du logging/tracing : simple exécutable local ou crate transverse commune lorsque plusieurs runtimes partagent subscriber, sinks ou policy ;
  12. les exceptions éventuelles au profil Rust strict ; pour une nouvelle baseline contrôlée, la façade crate-root et les chemins explicites sont sélectionnés par défaut, tandis que les audits de style supplémentaires restent décidés séparément ;
  13. les validations Cargo réellement nécessaires au code et aux manifests créés.

Les valeurs 0.1.0, 2024, project-name, project-core-lib, les seuils Clippy et les chemins de build présents dans les templates sont des exemples ou baselines à revoir. Ils ne deviennent jamais des valeurs universelles par simple copie.

Matérialisation du workspace

Fondation gouvernée

Appliquer d'abord la fondation 001 et résoudre ses décisions générales. Ne recopier ni le workflow ni la structure documentaire complète de PGR lorsqu'ils ne sont pas nécessaires au projet destinataire.

La version canonique du release unit doit être décidée avant d'adapter les manifests. Pour un train de release Cargo unique, [workspace.package].version reflète cette version selon 510-RUST_CARGO.md.

Manifest workspace

Copier templates/rust-cargo/Cargo.toml vers Cargo.toml, puis :

  • adapter le header # file: et démarrer la révision locale selon la convention documentaire retenue ;
  • remplacer members par les packages réellement présents ;
  • remplacer la version d'exemple par la version du release unit lorsque le workspace partage une seule release ;
  • aligner edition et resolver sur la toolchain réellement choisie ;
  • décider explicitement publish et les métadonnées communes ;
  • ajouter sous [workspace.dependencies] uniquement les dépendances réellement partagées ;
  • conserver, adapter ou documenter les niveaux de lints selon le profil local retenu.

Le projet ne doit pas remplir les champs manquants avec des identités fictives provenant de PGR, KSP ou Games.

Packages membres

Pour chaque crate réellement nécessaire, utiliser templates/rust-cargo/crates/project-core-lib/Cargo.toml comme exemple de manifest membre puis adapter son chemin et son nom.

project-core-lib n'est pas un nom de crate imposé. Dans une nouvelle baseline contrôlée, remplacer project par le nom court/abréviation du projet et choisir une responsabilité puis un rôle/cible lisibles conformément à 510-RUST_CARGO.md. Une crate bibliothèque, binaire ou spécialisée doit conserver le layout et les héritages qui correspondent à son rôle réel ; un suffixe n'est pas ajouté uniquement pour obtenir une symétrie artificielle.

Avant de créer une paire *-api / *-lib, démontrer la frontière contractuelle qui justifie deux packages. Une implémentation unique sans extension/backend/lifecycle séparé reste normalement une seule crate -lib. À l'inverse, une vraie crate -api reste principalement déclarative et ne reçoit pas le runtime de logging du projet par automatisme.

Les exécutables sont des packages distincts des bibliothèques qu'ils composent, sauf exception de framework sélectionnée. Leur main.rs reste mince. Si plusieurs crates runtime partagent la même configuration de diagnostics, prévoir une crate transverse de logging/tracing ; ne pas répliquer l'initialisation du subscriber dans chaque binaire ou bibliothèque.

Lorsque le membre hérite de la politique commune, version.workspace = true, edition.workspace = true, publish.workspace = true et [lints] workspace = true restent cohérents. Une exception locale, notamment de lint ou de safety, doit suivre le contrat de 510-RUST_CARGO.md et ne pas affaiblir silencieusement les autres membres.

Le code source minimal requis par Cargo appartient au projet destinataire. PGR ne fournit pas de src/lib.rs ou src/main.rs universel, car leur contenu dépend du rôle réel de la crate.

Outillage Rust/Cargo

Copier et adapter :

rustfmt.toml
clippy.toml
.cargo/config.toml

Suivre ../templates/001-RUST_CARGO_TOOLING.md pour leurs décisions d'adaptation.

L'édition de rustfmt.toml doit rester cohérente avec le workspace. Les seuils de clippy.toml doivent être revus au regard des API réelles. Dans .cargo/config.toml, remplacer project-name ou choisir un autre emplacement d'artefacts ; ne pas copier un chemin machine ou un identifiant appartenant à un autre projet.

Cargo.lock

Décider explicitement si Cargo.lock est versionné selon le type de produit, le mode de publication et le besoin de reproductibilité. La présence ou l'absence du lockfile dans un projet source historique ne constitue pas une règle suffisante pour le nouveau workspace.

Audits Rust facultatifs

Si le projet adopte les conventions documentées dans ../validation/002-RUST_STYLE_AUDITS.md, copier les scripts de style concernés et adapter leurs headers à leurs chemins locaux. La sélection des fichiers doit rester explicite. En particulier, l'audit des blocs de constantes ne doit jamais réordonner une table de protocole, une séquence de migrations ou toute autre structure dont l'ordre possède une sémantique propre.

Pour une nouvelle baseline contrôlée, le contrat de façade décrit dans ../validation/003-RUST_EXPORT_COMPLETENESS.md appartient au profil strict ; audit_rust_export_completeness.py avec _rust_audit_common.py SHOULD être adopté afin de contrôler les propriétés que rustc et Clippy ne possèdent pas. Une adoption d'un projet existant SHOULD commencer en --report-only, résoudre les écarts ou exceptions locales, puis seulement rendre l'audit bloquant.

Les audits de style de 002-RUST_STYLE_AUDITS.md restent séparés et ne sont copiés que lorsque leurs conventions sont retenues. Aucun script n'est copié uniquement parce qu'il existe dans PGR.

Validation initiale

Une instanciation minimale doit d'abord prouver que les manifests adaptés décrivent bien le workspace voulu, puis que les outils Rust/Cargo retenus acceptent la baseline réelle.

Lorsque la toolchain est disponible et que du code source minimal ou réel existe, la séquence normale comprend :

cargo metadata --format-version 1 --no-deps
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings

Ajouter des tests ciblés pour les crates qui possèdent déjà un comportement à vérifier. Un cargo build n'est nécessaire que lorsqu'un artefact de build doit réellement être produit.

Si des audits Rust facultatifs ont été sélectionnés, exécuter les audits de style après formatage sur les seuls chemins concernés et l'audit de façade sur la racine du projet une fois son contrat explicitement adopté.

La validation doit aussi confirmer :

CHECK  VERSION et workspace.package.version cohérents pour un train de release unique
CHECK  aucun placeholder project-name/project-core-lib non résolu dans les fichiers adoptés
CHECK  édition Rust cohérente entre Cargo.toml et rustfmt.toml
CHECK  membres du workspace existants, préfixés et nommés selon leur responsabilité/rôle
CHECK  édition Rust 2024 ou exception externe explicitement documentée
CHECK  profil strict de chemins/façade appliqué ou override borné documenté
CHECK  politique Cargo.lock explicitement décidée
CHECK  artefacts Cargo hors des livraisons source selon la politique locale
REVIEW dépendances/features, lints et métadonnées réellement nécessaires
REVIEW aucune specialization plateforme/framework ajoutée sans besoin réel

Pour valider les templates PGR eux-mêmes, une instanciation temporaire minimale peut remplacer les placeholders, créer une crate source triviale et exécuter les commandes Cargo ci-dessus. Cette preuve vérifie l'adoption des templates sans transformer le dépôt PGR en workspace Rust.

Une prévalidation PGR ou générateur ne remplace jamais la gate opérateur autoritaire du projet destinataire.

Ordre de composition et extensions

La specialization Rust/Cargo doit être appliquée après 001 lorsqu'elle l'utilise comme fondation. Les profils plateforme ou framework viennent ensuite uniquement s'ils sont applicables.

Une specialization plus précise peut :

  • ajouter des packages ou cibles spécifiques ;
  • imposer une matrice de toolchain ou de SDK ;
  • raffiner la politique d'artefacts ou de lockfile ;
  • ajouter des features, dépendances ou validations propres à son scope ;
  • définir une exception locale de safety strictement justifiée.

Elle ne doit pas réécrire les règles générales Cargo ou inventer un nouveau workspace composite si les owners existants suffisent.

Overrides et exceptions

Toute divergence par rapport aux templates ou au profil 510 doit identifier le choix concerné, son scope et sa raison lorsqu'elle affecte le contrat durable du projet.

Un projet peut notamment choisir un layout sans crates/, un autre chemin d'artefacts, une autre largeur Rustfmt, une politique de lockfile différente, des seuils Clippy différents ou une crate à lints locaux. Ces choix restent locaux et ne modifient pas les defaults PGR pour les autres projets.

Hors scope

Cette specification ne définit pas :

  • un nom universel de workspace ou de crate ;
  • une version Rust ou Cargo exacte à pinner sans justification ;
  • une liste universelle de dépendances ou features ;
  • une politique Cargo.lock identique pour bibliothèques et applications ;
  • une architecture applicative au-delà du workspace Cargo ;
  • une plateforme, un framework, WASM, Android, Tauri ou une FFI ;
  • un CI/CD, packaging ou mécanisme de publication universel ;
  • une obligation de copier les audits Rust facultatifs ;
  • un src/lib.rs ou src/main.rs générique sans rôle réel.

Les spécialisations futures doivent rester composables au-dessus de ce skeleton plutôt que modifier rétroactivement son scope.