# 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`](001-PROJECT_GOVERNANCE_FOUNDATION.md), sélectionne les profils [`../rules/500-LANGUAGES.md`](../rules/500-LANGUAGES.md) et [`../rules/510-RUST_CARGO.md`](../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`](../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 : ```text 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 : ```text 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 : ```text 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`](../validation/002-RUST_STYLE_AUDITS.md) et [`../validation/003-RUST_EXPORT_COMPLETENESS.md`](../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 : ```text rustfmt.toml clippy.toml .cargo/config.toml ``` Suivre [`../templates/001-RUST_CARGO_TOOLING.md`](../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`](../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`](../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 : ```bash 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 : ```text 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.