From a1b56af8edfc24dd7f55a8a5876ccedc8e142a81 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Mon, 28 Sep 2026 10:02:47 +0200 Subject: [PATCH] 0.0.1-alpha.5.fix.1 --- CHANGELOG.md | 3 +- Cargo.lock | 14 +- Cargo.toml | 4 +- RULES.md | 23 +++- VERSION | 2 +- crates/knowledge-domain-lib/src/lib.rs | 5 +- crates/knowledge-domain-lib/src/source.rs | 6 +- .../unit_tests.rs => unit_tests/source.rs} | 4 +- crates/knowledge-git-api/src/lib.rs | 5 +- .../{src/unit_tests.rs => unit_tests/lib.rs} | 2 +- crates/knowledge-sync-api/src/lib.rs | 5 +- .../{src/unit_tests.rs => unit_tests/lib.rs} | 2 +- crates/knowledge-web-lib/src/assets.rs | 6 +- crates/knowledge-web-lib/src/lib.rs | 5 +- crates/knowledge-web-lib/src/page.rs | 6 +- .../unit_tests.rs => unit_tests/assets.rs} | 24 +--- crates/knowledge-web-lib/unit_tests/page.rs | 24 ++++ deltas/0.0.1/alpha.5.fix.1.md | 130 ++++++++++++++++++ docs/plans/001-V0_0_1_FOUNDATION_PLAN.md | 14 +- docs/validation/001-VALIDATION_MATRIX.md | 49 ++++++- history/0.0.1/alpha.5.fix.1.md | 63 +++++++++ manifests/0.0.1/alpha.5.fix.1.delete.txt | 4 + scripts/audit_rust_test_layout.py | 82 +++++++++++ 23 files changed, 427 insertions(+), 55 deletions(-) rename crates/knowledge-domain-lib/{src/unit_tests.rs => unit_tests/source.rs} (91%) rename crates/knowledge-git-api/{src/unit_tests.rs => unit_tests/lib.rs} (96%) rename crates/knowledge-sync-api/{src/unit_tests.rs => unit_tests/lib.rs} (96%) rename crates/knowledge-web-lib/{src/unit_tests.rs => unit_tests/assets.rs} (67%) create mode 100644 crates/knowledge-web-lib/unit_tests/page.rs create mode 100644 deltas/0.0.1/alpha.5.fix.1.md create mode 100644 history/0.0.1/alpha.5.fix.1.md create mode 100644 manifests/0.0.1/alpha.5.fix.1.delete.txt create mode 100644 scripts/audit_rust_test_layout.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f774ae3..5c3a641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ - + # Changelog SaseDev Knowledge @@ -17,6 +17,7 @@ Ce fichier décrit les changements utiles des releases publiées. Les détails d - instancie le workspace Rust/Cargo strict avec une première crate de domaine et une politique explicite de `Cargo.lock` versionné ; - introduit les premiers contrats provider-neutral de source, Git et synchronisation sans dépendance à une forge ni à PostgreSQL ; - active les audits Rust PGR de structure et de façade au moment où des API publiques réelles apparaissent ; +- sélectionne localement `unit_tests/` hors de `src/` pour tous les tests unitaires Rust, avec `tests/` réservé aux tests d'intégration Cargo ; - fixe le frontend Web PGR comme laboratoire de validation des templates statiques et des assets avant adaptation du markup runtime en Maud ; - matérialise ce laboratoire sous `Web/knowledge-template-lab/` avec npm, TypeScript strict, Vite, Sass, Bootstrap et manifest Vite ; - retient l’intégration production Actix/Maud via le manifest Vite comme contrat d’asset mapping à réimplémenter proprement, sans copier mécaniquement le corpus historique ; diff --git a/Cargo.lock b/Cargo.lock index ca0d690..d503538 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,46 +475,46 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "knowledge-domain-lib" -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" [[package]] name = "knowledge-git-api" -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" dependencies = [ "knowledge-domain-lib", ] [[package]] name = "knowledge-howtos-server" -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" dependencies = [ "knowledge-web-lib", ] [[package]] name = "knowledge-pgr-server" -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" dependencies = [ "knowledge-web-lib", ] [[package]] name = "knowledge-snippets-server" -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" dependencies = [ "knowledge-web-lib", ] [[package]] name = "knowledge-sync-api" -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" dependencies = [ "knowledge-domain-lib", ] [[package]] name = "knowledge-web-lib" -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" dependencies = [ "actix-files", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index cc6f808..26ce1d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ # file: Cargo.toml -# version: 9 +# version: 10 [workspace] resolver = "3" @@ -14,7 +14,7 @@ members = [ ] [workspace.package] -version = "0.0.1-alpha.5" +version = "0.0.1-alpha.5.fix.1" edition = "2024" publish = false repository = "https://git.sasedev.com/Sasedev/sasedev-knowledge" diff --git a/RULES.md b/RULES.md index b249452..8550039 100644 --- a/RULES.md +++ b/RULES.md @@ -1,5 +1,5 @@ - + # Règles SaseDev Knowledge @@ -183,6 +183,27 @@ Les trois launchers MUST recevoir leur socket de bind par configuration (`KNOWLE ## Rust et crates +Knowledge sélectionne localement la convention `unit_tests/` séparée que PGR `0.1.1` autorise sans l'imposer globalement. + +Pour toutes les crates Rust de ce workspace : + +- les tests d'intégration Cargo MUST résider sous `tests/` et consommer l'API publique de la crate ; +- les tests unitaires MUST résider sous `unit_tests/` à la racine de la crate, en miroir logique de `src/` ; +- `src/` MUST NOT contenir de fichier d'implémentation de tests unitaires ni d'attribut `#[test]` ; +- un module source rattache son fichier de tests avec `#[cfg(test)]` et `#[path = "../unit_tests/.rs"]` ou le chemin miroir équivalent ; +- les tests unitaires d'un item partagé continuent d'utiliser son identité crate-root conformément à PGR ; +- `tests/` MUST NOT être utilisé pour contourner la visibilité interne ou héberger des tests unitaires qui dépendent d'éléments privés. + +Exemple : + +```rust +#[cfg(test)] +#[path = "../unit_tests/bite.rs"] +mod tests; +``` + +Cette convention locale est plus stricte que le `MAY` générique de PGR, mais reste conforme à celui-ci. Si PGR doit l'imposer à tous les futurs workspaces, cette évolution appartient à une version ultérieure du référentiel PGR et non à Knowledge. + Le préfixe de crate retenu est `knowledge-`. Les responsabilités candidates sont documentées dans l'architecture. Une crate n'est matérialisée que lorsqu'elle possède une responsabilité réelle. Le suffixe `-api` n'est utilisé que pour une frontière passive dont des implémentations distinctes/remplaçables sont réellement prévues. diff --git a/VERSION b/VERSION index aa5f806..d8849ff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.1-alpha.5 +0.0.1-alpha.5.fix.1 diff --git a/crates/knowledge-domain-lib/src/lib.rs b/crates/knowledge-domain-lib/src/lib.rs index c73dace..604bb76 100644 --- a/crates/knowledge-domain-lib/src/lib.rs +++ b/crates/knowledge-domain-lib/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/knowledge-domain-lib/src/lib.rs -// version: 2 +// version: 3 //! Shared domain contracts for SaseDev Knowledge. //! @@ -11,6 +11,3 @@ mod source; pub use crate::content_family::ContentFamily; pub use crate::source::{ContentSource, SourceId, SourceIdError}; - -#[cfg(test)] -mod unit_tests; diff --git a/crates/knowledge-domain-lib/src/source.rs b/crates/knowledge-domain-lib/src/source.rs index df4fe4c..19e4074 100644 --- a/crates/knowledge-domain-lib/src/source.rs +++ b/crates/knowledge-domain-lib/src/source.rs @@ -1,5 +1,5 @@ // file: crates/knowledge-domain-lib/src/source.rs -// version: 2 +// version: 3 //! Source identities independent of repository and forge providers. @@ -66,3 +66,7 @@ impl crate::ContentSource { return self.family; } } + +#[cfg(test)] +#[path = "../unit_tests/source.rs"] +mod tests; diff --git a/crates/knowledge-domain-lib/src/unit_tests.rs b/crates/knowledge-domain-lib/unit_tests/source.rs similarity index 91% rename from crates/knowledge-domain-lib/src/unit_tests.rs rename to crates/knowledge-domain-lib/unit_tests/source.rs index a61b160..083a83a 100644 --- a/crates/knowledge-domain-lib/src/unit_tests.rs +++ b/crates/knowledge-domain-lib/unit_tests/source.rs @@ -1,5 +1,5 @@ -// file: crates/knowledge-domain-lib/src/unit_tests.rs -// version: 2 +// file: crates/knowledge-domain-lib/unit_tests/source.rs +// version: 1 #[test] fn source_id_rejects_empty_values() { diff --git a/crates/knowledge-git-api/src/lib.rs b/crates/knowledge-git-api/src/lib.rs index 2d38875..d83ed0b 100644 --- a/crates/knowledge-git-api/src/lib.rs +++ b/crates/knowledge-git-api/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/knowledge-git-api/src/lib.rs -// version: 1 +// version: 2 //! Provider-neutral contracts for Git-backed Knowledge sources. //! @@ -54,4 +54,5 @@ pub trait GitRepository { } #[cfg(test)] -mod unit_tests; +#[path = "../unit_tests/lib.rs"] +mod tests; diff --git a/crates/knowledge-git-api/src/unit_tests.rs b/crates/knowledge-git-api/unit_tests/lib.rs similarity index 96% rename from crates/knowledge-git-api/src/unit_tests.rs rename to crates/knowledge-git-api/unit_tests/lib.rs index 76a5c9c..370fb37 100644 --- a/crates/knowledge-git-api/src/unit_tests.rs +++ b/crates/knowledge-git-api/unit_tests/lib.rs @@ -1,4 +1,4 @@ -// file: crates/knowledge-git-api/src/unit_tests.rs +// file: crates/knowledge-git-api/unit_tests/lib.rs // version: 1 #[derive(Debug, Eq, PartialEq)] diff --git a/crates/knowledge-sync-api/src/lib.rs b/crates/knowledge-sync-api/src/lib.rs index 6cdef12..3f64e0b 100644 --- a/crates/knowledge-sync-api/src/lib.rs +++ b/crates/knowledge-sync-api/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/knowledge-sync-api/src/lib.rs -// version: 1 +// version: 2 //! Contracts for provider-neutral repository synchronization signals. //! @@ -54,4 +54,5 @@ pub trait RepositoryEventSource { } #[cfg(test)] -mod unit_tests; +#[path = "../unit_tests/lib.rs"] +mod tests; diff --git a/crates/knowledge-sync-api/src/unit_tests.rs b/crates/knowledge-sync-api/unit_tests/lib.rs similarity index 96% rename from crates/knowledge-sync-api/src/unit_tests.rs rename to crates/knowledge-sync-api/unit_tests/lib.rs index 96c9d2c..e051dd5 100644 --- a/crates/knowledge-sync-api/src/unit_tests.rs +++ b/crates/knowledge-sync-api/unit_tests/lib.rs @@ -1,4 +1,4 @@ -// file: crates/knowledge-sync-api/src/unit_tests.rs +// file: crates/knowledge-sync-api/unit_tests/lib.rs // version: 1 #[derive(Debug, Eq, PartialEq)] diff --git a/crates/knowledge-web-lib/src/assets.rs b/crates/knowledge-web-lib/src/assets.rs index 3d3437d..c4ed83a 100644 --- a/crates/knowledge-web-lib/src/assets.rs +++ b/crates/knowledge-web-lib/src/assets.rs @@ -1,5 +1,5 @@ // file: crates/knowledge-web-lib/src/assets.rs -// version: 1 +// version: 2 //! Vite development and production asset resolution. @@ -193,3 +193,7 @@ fn local_static_mount_path(base: &str) -> Option { } return Some(format!("{}/assets", normalized.trim_end_matches('/'))); } + +#[cfg(test)] +#[path = "../unit_tests/assets.rs"] +mod tests; diff --git a/crates/knowledge-web-lib/src/lib.rs b/crates/knowledge-web-lib/src/lib.rs index 251beec..aca23ba 100644 --- a/crates/knowledge-web-lib/src/lib.rs +++ b/crates/knowledge-web-lib/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/knowledge-web-lib/src/lib.rs -// version: 1 +// version: 2 //! Shared Actix Web and Maud composition for the three Knowledge server launchers. //! @@ -22,6 +22,3 @@ pub(crate) use self::assets::ViteAssets; pub(crate) use self::assets::load_assets_from_environment; /// Internal Maud renderer for the public foundation page. pub(crate) use self::page::render_index_page; - -#[cfg(test)] -mod unit_tests; diff --git a/crates/knowledge-web-lib/src/page.rs b/crates/knowledge-web-lib/src/page.rs index 160b701..6b649e2 100644 --- a/crates/knowledge-web-lib/src/page.rs +++ b/crates/knowledge-web-lib/src/page.rs @@ -1,5 +1,5 @@ // file: crates/knowledge-web-lib/src/page.rs -// version: 1 +// version: 2 //! Maud rendering adapted from the static template-lab contract. @@ -50,3 +50,7 @@ fn family_slug(family: knowledge_domain_lib::ContentFamily) -> &'static str { knowledge_domain_lib::ContentFamily::ProjectLocal => return "project-local", } } + +#[cfg(test)] +#[path = "../unit_tests/page.rs"] +mod tests; diff --git a/crates/knowledge-web-lib/src/unit_tests.rs b/crates/knowledge-web-lib/unit_tests/assets.rs similarity index 67% rename from crates/knowledge-web-lib/src/unit_tests.rs rename to crates/knowledge-web-lib/unit_tests/assets.rs index 4e63e3f..af01aaa 100644 --- a/crates/knowledge-web-lib/src/unit_tests.rs +++ b/crates/knowledge-web-lib/unit_tests/assets.rs @@ -1,7 +1,7 @@ -// file: crates/knowledge-web-lib/src/unit_tests.rs +// file: crates/knowledge-web-lib/unit_tests/assets.rs // version: 1 -//! Unit tests for shared Web composition primitives. +//! Unit tests for Vite asset resolution. #[test] fn development_assets_include_vite_client_before_main_entry() { @@ -50,23 +50,3 @@ fn manifest_requires_the_stable_main_entry() { let result = crate::ViteAssets::from_manifest_text(manifest, "/", std::path::PathBuf::from("/tmp/knowledge-assets")); assert!(result.is_err()); } - -#[test] -fn maud_page_uses_resolved_assets_and_site_identity() { - let assets = match crate::ViteAssets::from_manifest_text( - r#"{"src/main.ts": {"file": "assets/main.js", "css": ["assets/main.css"], "isEntry": true}}"#, - "/", - std::path::PathBuf::from("/tmp/knowledge-assets"), - ) { - Ok(value) => value, - Err(error) => { - assert!(error.is_empty(), "unexpected manifest error: {error}"); - return; - }, - }; - let rendered = crate::render_index_page(crate::ServerSite::Pgr, &assets).into_string(); - assert!(rendered.contains("SaseDev Knowledge — PGR")); - assert!(rendered.contains("/assets/main.js")); - assert!(rendered.contains("/assets/main.css")); - assert!(rendered.contains("data-content-family=\"pgr\"")); -} diff --git a/crates/knowledge-web-lib/unit_tests/page.rs b/crates/knowledge-web-lib/unit_tests/page.rs new file mode 100644 index 0000000..2801dfa --- /dev/null +++ b/crates/knowledge-web-lib/unit_tests/page.rs @@ -0,0 +1,24 @@ +// file: crates/knowledge-web-lib/unit_tests/page.rs +// version: 1 + +//! Unit tests for Maud page rendering. + +#[test] +fn maud_page_uses_resolved_assets_and_site_identity() { + let assets = match crate::ViteAssets::from_manifest_text( + r#"{"src/main.ts": {"file": "assets/main.js", "css": ["assets/main.css"], "isEntry": true}}"#, + "/", + std::path::PathBuf::from("/tmp/knowledge-assets"), + ) { + Ok(value) => value, + Err(error) => { + assert!(error.is_empty(), "unexpected manifest error: {error}"); + return; + }, + }; + let rendered = crate::render_index_page(crate::ServerSite::Pgr, &assets).into_string(); + assert!(rendered.contains("SaseDev Knowledge — PGR")); + assert!(rendered.contains("/assets/main.js")); + assert!(rendered.contains("/assets/main.css")); + assert!(rendered.contains("data-content-family=\"pgr\"")); +} diff --git a/deltas/0.0.1/alpha.5.fix.1.md b/deltas/0.0.1/alpha.5.fix.1.md new file mode 100644 index 0000000..35c1716 --- /dev/null +++ b/deltas/0.0.1/alpha.5.fix.1.md @@ -0,0 +1,130 @@ + + + +# Delta 0.0.1-alpha.5.fix.1 — layout séparé des tests unitaires Rust + +## Base requise + +État `0.0.1-alpha.5` committé et poussé après application du history : + +```text +history/0.0.1/alpha.5.md = FAIL +``` + +La version devient : + +```text +0.0.1-alpha.5.fix.1 +``` + +## Cause + +La gate technique d'`alpha.5` passe, y compris les tests de `knowledge-web-lib` et les smokes HTTP. + +La revue de gouvernance opérateur relève cependant que les tests unitaires restent sous `src/unit_tests.rs`. + +PGR `0.1.1` autorise une arborescence `unit_tests/` séparée avec la modalité `MAY`. Knowledge sélectionne désormais explicitement cette convention comme règle locale `MUST`. + +Le défaut concerne quatre crates et doit être corrigé de manière cohérente. + +## Arborescence cible + +```text +crates// + src/ + unit_tests/ + tests/ +``` + +- `unit_tests/` : tests unitaires attachés aux modules source par `#[path = "..."]` ; +- `tests/` : tests d'intégration Cargo qui consomment l'API publique. + +Exemple : + +```rust +#[cfg(test)] +#[path = "../unit_tests/source.rs"] +mod tests; +``` + +## ADD + +```text +crates/knowledge-domain-lib/unit_tests/source.rs +crates/knowledge-git-api/unit_tests/lib.rs +crates/knowledge-sync-api/unit_tests/lib.rs +crates/knowledge-web-lib/unit_tests/assets.rs +crates/knowledge-web-lib/unit_tests/page.rs +scripts/audit_rust_test_layout.py +manifests/0.0.1/alpha.5.fix.1.delete.txt +deltas/0.0.1/alpha.5.fix.1.md +``` + +## REPLACE + +```text +VERSION +Cargo.toml +CHANGELOG.md +RULES.md +crates/knowledge-domain-lib/src/lib.rs +crates/knowledge-domain-lib/src/source.rs +crates/knowledge-git-api/src/lib.rs +crates/knowledge-sync-api/src/lib.rs +crates/knowledge-web-lib/src/lib.rs +crates/knowledge-web-lib/src/assets.rs +crates/knowledge-web-lib/src/page.rs +docs/plans/001-V0_0_1_FOUNDATION_PLAN.md +docs/validation/001-VALIDATION_MATRIX.md +``` + +## DELETE + +```text +crates/knowledge-domain-lib/src/unit_tests.rs +crates/knowledge-git-api/src/unit_tests.rs +crates/knowledge-sync-api/src/unit_tests.rs +crates/knowledge-web-lib/src/unit_tests.rs +``` + +Les suppressions sont possédées par : + +```text +manifests/0.0.1/alpha.5.fix.1.delete.txt +``` + +## Audit ajouté + +`audit_rust_test_layout.py` vérifie : + +- absence de `#[test]` sous `src/` ; +- absence de fichiers `src/tests.rs` et `src/unit_tests.rs` ; +- absence de `mod unit_tests;` classique ; +- rattachement effectif de chaque fichier sous `unit_tests/` par un `#[path = "..."]`. + +L'audit ne traite pas `tests/` comme tests internes. + +## Scope fonctionnel + +Aucun comportement métier ou HTTP n'est modifié. + +Les routes, assets, rendu Maud, manifest Vite, binds et trois launchers restent identiques à `alpha.5`. + +## Application des suppressions + +Après extraction du delta, appliquer exactement le manifest : + +```bash +while IFS= read -r path; do + test -n "$path" || continue + rm -f -- "$path" +done < manifests/0.0.1/alpha.5.fix.1.delete.txt +``` + +Ne pas supprimer d'autre chemin. + +## Validation attendue + +La gate doit prouver l'arborescence, les rattachements, les audits Rust, Cargo/Clippy/tests, la baseline Web et les trois smokes HTTP. + +Ne pas committe `alpha.5.fix.1` avant production de son history à partir des résultats opérateur. diff --git a/docs/plans/001-V0_0_1_FOUNDATION_PLAN.md b/docs/plans/001-V0_0_1_FOUNDATION_PLAN.md index b6aca8c..8659bfd 100644 --- a/docs/plans/001-V0_0_1_FOUNDATION_PLAN.md +++ b/docs/plans/001-V0_0_1_FOUNDATION_PLAN.md @@ -1,5 +1,5 @@ - + # Plan 0.0.1 — fondation SaseDev Knowledge @@ -203,6 +203,18 @@ La gate doit couvrir les tests `knowledge-web-lib`, la compilation/Clippy des qu La tranche ne doit pas introduire admin complète, auth complète, persistance métier complète, logging transverse artificiel ni forge obligatoire. +La gate technique d'`alpha.5` est verte : structure, Web, Cargo, Clippy, tests et smokes HTTP passent. La tranche reste néanmoins **FAIL** après revue opérateur de gouvernance : les tests unitaires sont encore implémentés sous `src/unit_tests.rs`, alors que Knowledge sélectionne désormais la convention PGR optionnelle `unit_tests/` séparée et miroir de `src/`. + +Le défaut existait déjà dans les trois crates antérieures et est également introduit par `knowledge-web-lib`; il doit donc être corrigé globalement et non seulement dans la nouvelle crate. + +`alpha.5.fix.1` : + +- formalise cette convention locale comme `MUST` dans `RULES.md` ; +- déplace les tests unitaires des quatre crates concernées sous `unit_tests/` ; +- rattache les tests avec `#[cfg(test)]` + `#[path = "..."]` ; +- conserve `tests/` pour les tests d'intégration Cargo uniquement ; +- ajoute un audit monotâche empêchant le retour de `#[test]` ou de fichiers `unit_tests.rs` sous `src/`. + ### beta.1 — réconciliation de fondation Rejouer les gates pertinentes, réconcilier docs/architecture avec ce qui existe réellement, traiter les décisions devenues nécessaires et effectuer la revue d'horizon. diff --git a/docs/validation/001-VALIDATION_MATRIX.md b/docs/validation/001-VALIDATION_MATRIX.md index 0704ab4..7f05fd5 100644 --- a/docs/validation/001-VALIDATION_MATRIX.md +++ b/docs/validation/001-VALIDATION_MATRIX.md @@ -1,5 +1,5 @@ - + # Matrice de validation Knowledge @@ -316,3 +316,50 @@ La composition serveur doit prouver : - audits Rust PGR, `cargo check`, Clippy strict et tests ciblés `PASS` ; - smoke HTTP production `PASS` pour les trois launchers avec ports de test injectés par environnement ; - `Cargo.lock` mis à jour/versionné et staging propre. + +## Convention locale des tests Rust + +Knowledge sélectionne la convention PGR optionnelle suivante comme règle locale obligatoire : + +```text +crate/ + src/ + unit_tests/ + tests/ +``` + +`unit_tests/` contient les tests unitaires attachés aux modules source par `#[path = "..."]`. + +`tests/` contient exclusivement les tests d'intégration Cargo qui consomment l'API publique. + +La gate Rust ajoute : + +```text +python3 -B scripts/audit_rust_test_layout.py crates +``` + +Cet audit doit refuser notamment : + +- un attribut `#[test]` dans `src/` ; +- un fichier `src/unit_tests.rs` ou `src/tests.rs` ; +- un `mod unit_tests;` classique sous `src/` ; +- un fichier sous `unit_tests/` qui n'est référencé par aucun `#[path = "..."]` d'un source de la crate. + +## Gate de `0.0.1-alpha.5.fix.1` + +Le fix de layout des tests doit prouver : + +- `VERSION = 0.0.1-alpha.5.fix.1` et version workspace identique ; +- history `alpha.5` `FAIL` committé avant application ; +- suppression exacte des quatre anciens `src/unit_tests.rs` via le manifest de suppression ; +- tests unitaires sous `unit_tests/` hors de `src/` pour `knowledge-domain-lib`, `knowledge-git-api`, `knowledge-sync-api` et `knowledge-web-lib` ; +- rattachements `#[cfg(test)]` + `#[path = "..."]` depuis les modules source propriétaires ; +- aucun `#[test]` sous `crates/*/src/` ; +- `tests/` réservé aux futurs tests d'intégration Cargo ; +- `audit_rust_test_layout.py` `PASS` ; +- audits Rust PGR existants toujours `PASS`, y compris export completeness qui suit les modules `#[path]` ; +- `cargo check`, Clippy strict et `cargo test --workspace --all-targets --all-features` `PASS` ; +- baseline Web `npm ci`, typecheck et build `PASS` ; +- smoke HTTP production des trois serveurs `PASS` ; +- aucune modification fonctionnelle Actix/Maud/Vite au-delà du rattachement des tests ; +- `git diff --cached --check` propre. diff --git a/history/0.0.1/alpha.5.fix.1.md b/history/0.0.1/alpha.5.fix.1.md new file mode 100644 index 0000000..bd7a988 --- /dev/null +++ b/history/0.0.1/alpha.5.fix.1.md @@ -0,0 +1,63 @@ + + + +# History 0.0.1-alpha.5.fix.1 — layout séparé des tests unitaires Rust + +## Statut + +FAIL + +La gate opérateur de `0.0.1-alpha.5.fix.1` exécutée le `2026-09-28` confirme la migration fonctionnelle des tests unitaires hors de `src/`, mais le premier contrôle d'hygiène Git échoue sur deux lignes vides terminales. + +## Baseline opérateur + +`alpha.5` `FAIL` a été historisé, committé et poussé avant application du fix : + +```text +history/0.0.1/alpha.5.md = FAIL +commit c17b706 +message 0.0.1-alpha.5 +branch master +push origin/master PASS +status clean après push +``` + +Le push observé a avancé `origin/master` de `8f6f072` à `c17b706`. + +## Layout des tests + +Le manifest de suppression contient exactement les quatre anciens `src/unit_tests.rs`, qui sont supprimés avant la gate. La preuve structurelle passe : + +```text +Knowledge 0.0.1-alpha.5.fix.1 test layout: clean +Rust test-layout audit: clean (7 crate(s)) +``` + +Les cinq fichiers unitaires résident désormais sous `unit_tests/` et leurs tests apparaissent sous les modules propriétaires (`source::tests`, `assets::tests`, `page::tests`). + +## Défaut bloquant initial + +Le premier `git diff --check` échoue avec : + +```text +crates/knowledge-domain-lib/src/lib.rs:14: new blank line at EOF. +crates/knowledge-web-lib/src/lib.rs:25: new blank line at EOF. +``` + +La tranche reste donc `FAIL`. + +## Normalisation et preuves suivantes + +`cargo fmt --all` puis `cargo fmt --all -- --check` passent et normalisent les fins de fichiers. Les audits Rust passent sur 18 fichiers et 7 crates/packages. `cargo check`, Clippy strict et tous les tests workspace passent : 3 + 1 + 1 + 4 tests, launchers à 0 test. + +La baseline Web passe également : `npm ci`, typecheck et build Vite. Les warnings Sass Bootstrap et `@parcel/watcher@2.6.0` restent des observations non bloquantes déjà connues. + +Le transcript du fix ne contient pas le rejeu demandé des trois smokes HTTP. La preuve historique d'`alpha.5` ne remplace pas cette preuve de fix. + +Le `git diff --cached --check` final est propre et le staging reflète les renommages/suppressions gouvernés ainsi que les cinq fichiers `unit_tests/`. + +## Décision + +`0.0.1-alpha.5.fix.1` est `FAIL`. + +La transition autorisée est `0.0.1-alpha.5.fix.2`, depuis le snapshot FAIL déjà normalisé, avec gate sans formatage mutateur préalable et trois smokes HTTP explicitement rejoués. diff --git a/manifests/0.0.1/alpha.5.fix.1.delete.txt b/manifests/0.0.1/alpha.5.fix.1.delete.txt new file mode 100644 index 0000000..6255f93 --- /dev/null +++ b/manifests/0.0.1/alpha.5.fix.1.delete.txt @@ -0,0 +1,4 @@ +crates/knowledge-domain-lib/src/unit_tests.rs +crates/knowledge-git-api/src/unit_tests.rs +crates/knowledge-sync-api/src/unit_tests.rs +crates/knowledge-web-lib/src/unit_tests.rs diff --git a/scripts/audit_rust_test_layout.py b/scripts/audit_rust_test_layout.py new file mode 100644 index 0000000..7375830 --- /dev/null +++ b/scripts/audit_rust_test_layout.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# file: scripts/audit_rust_test_layout.py +# version: 1 + +"""Audit the Knowledge Rust unit/integration test layout.""" + +from __future__ import annotations + +import argparse +import pathlib +import re +import sys + +_TEST_ATTRIBUTE = re.compile(r"(?m)^\s*#\s*\[\s*test\s*\]") +_PATH_ATTRIBUTE = re.compile(r'#\s*\[\s*path\s*=\s*"([^"]+)"\s*\]') +_FORBIDDEN_MODULE = re.compile(r"(?m)^\s*mod\s+unit_tests\s*;") + + +def audit_crate(crate_root: pathlib.Path) -> list[str]: + """Return layout violations for one crate.""" + errors: list[str] = [] + src_root = crate_root / "src" + referenced_unit_tests: set[pathlib.Path] = set() + + if src_root.is_dir(): + for source in sorted(src_root.rglob("*.rs")): + text = source.read_text(encoding="utf-8") + relative = source.relative_to(crate_root) + + if _TEST_ATTRIBUTE.search(text): + errors.append(f"{crate_root.name}/{relative}: #[test] must live under unit_tests/") + + if source.name in {"tests.rs", "unit_tests.rs"}: + errors.append(f"{crate_root.name}/{relative}: test implementation file must not live under src/") + + if _FORBIDDEN_MODULE.search(text): + errors.append(f"{crate_root.name}/{relative}: use #[path = \"../unit_tests/...\"] instead of mod unit_tests;") + + for match in _PATH_ATTRIBUTE.finditer(text): + candidate = (source.parent / match.group(1)).resolve() + try: + candidate.relative_to((crate_root / "unit_tests").resolve()) + except ValueError: + continue + referenced_unit_tests.add(candidate) + + unit_root = crate_root / "unit_tests" + if unit_root.is_dir(): + for test_file in sorted(unit_root.rglob("*.rs")): + resolved = test_file.resolve() + if resolved not in referenced_unit_tests: + relative = test_file.relative_to(crate_root) + errors.append(f"{crate_root.name}/{relative}: unit test file is not attached by any #[path] module") + + return errors + + +def main() -> int: + """Run the audit.""" + parser = argparse.ArgumentParser() + parser.add_argument("root", nargs="?", default="crates") + arguments = parser.parse_args() + + root = pathlib.Path(arguments.root) + errors: list[str] = [] + crate_count = 0 + + for manifest in sorted(root.glob("*/Cargo.toml")): + crate_count += 1 + errors.extend(audit_crate(manifest.parent)) + + if errors: + for error in errors: + print(error, file=sys.stderr) + return 1 + + print(f"Rust test-layout audit: clean ({crate_count} crate(s))") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())