From 4a68a54d8533ae2319f5c6b8c5abeb48324d50e0 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Sun, 16 Aug 2026 10:01:04 +0200 Subject: [PATCH] v0.1.4-pre.002 --- Cargo.toml | 4 +- crates/ksp-config-lib/README.md | 8 +- crates/ksp-config-lib/TODO.md | 10 +- crates/ksp-config-lib/USAGE.md | 18 +- crates/ksp-config-lib/src/registry.rs | 9 +- crates/ksp-config-lib/tests/public_api.rs | 21 +- crates/ksp-config-lib/unit_tests/registry.rs | 55 +++++- deltas/0.1.4/pre.002.md | 194 +++++++++++++++++++ 8 files changed, 308 insertions(+), 11 deletions(-) create mode 100644 deltas/0.1.4/pre.002.md diff --git a/Cargo.toml b/Cargo.toml index 6db315a..6626f0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 62 +# version: 63 [workspace] resolver = "3" members = ["crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib"] [workspace.package] -version = "0.1.4-pre.1" +version = "0.1.4-pre.2" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-config-lib/README.md b/crates/ksp-config-lib/README.md index 57a11dc..0ba2756 100644 --- a/crates/ksp-config-lib/README.md +++ b/crates/ksp-config-lib/README.md @@ -1,5 +1,5 @@ - + # ksp-config-lib @@ -12,7 +12,7 @@ La crate centralise les documents JSON, leurs schemas, les profils et compositio `ksp-config-lib` possède : - le bootstrap non récursif `config/` / `config/schemas/` et les overrides `--cfgpath` / `--schemapath` ; -- le registre logique `file_id -> filename` et les overrides `--filemap==` ; +- le registre logique `file_id -> filename`, son inventaire public read-only ordonné par `file_id` et les overrides `--filemap==` ; - la lecture JSON et la validation JSON Schema Draft 2020-12 ; - les invariants sémantiques KSP des documents connus ; - les globals, `default_profile`, profils nommés et leur provenance ; @@ -27,7 +27,7 @@ La crate centralise les documents JSON, leurs schemas, les profils et compositio - les écritures atomiques JSON/`.env` et la protection des permissions `.env` ; - les audits workspace empêchant les bypass d'ownership Config et les oublis dans `.env.example`. -## Ressources gérées dans `0.1.3` +## Ressources gérées Le registre par défaut connaît : @@ -37,6 +37,8 @@ schema.std.logging -> config/schemas/std.logging.schema.json schema.composite -> config/schemas/composite.schema.json ``` +`ConfigFileRegistry::descriptors()` expose ces descripteurs en lecture seule et dans un ordre déterministe par `file_id`. Une application de management peut ainsi découvrir les fichiers connus sans maintenir une liste parallèle ni dépendre de leurs filenames physiques. + `config/examples/composite.example.json` démontre le format composite sans créer de composite runtime fictif. Le fichier local d'environnement est : diff --git a/crates/ksp-config-lib/TODO.md b/crates/ksp-config-lib/TODO.md index 9e44b42..f4155e4 100644 --- a/crates/ksp-config-lib/TODO.md +++ b/crates/ksp-config-lib/TODO.md @@ -1,5 +1,5 @@ - + # TODO ksp-config-lib @@ -9,7 +9,13 @@ Aucun TODO fonctionnel bloquant n'est ouvert pour la fondation Config `0.1.3`. Les responsabilités prévues pour cette release sont implémentées et couvertes par les tests : bootstrap, registre `file_id`, JSON/JSON Schema, profils, composites, environnement process/`.env`, placeholders, sensibilité/provenance, adapter Logging, management/persistence et audits d'ownership. -## Reporté explicitement à `0.1.4` +## Extensions bornées révélées par `0.1.4` + +`0.1.4-pre.002` ajoute l'inventaire public read-only de `ConfigFileRegistry`, nécessaire au shell Documents de `ksp-app-config-desk`. Le registre reste propriétaire des descripteurs ; l'application n'entretient pas de liste parallèle de `file_id`. + +La seconde lacune révélée pendant `pre.001` reste à traiter dans la tranche suivante : une API Config bornée permettant de soumettre le source corrigé d'un `file_id` connu, le valider puis le persister atomiquement sans accès filesystem direct de l'application. + +## Validation desktop de `0.1.4` La validation applicative desktop appartient à `ksp-app-config-desk` : diff --git a/crates/ksp-config-lib/USAGE.md b/crates/ksp-config-lib/USAGE.md index b0b725d..80708b6 100644 --- a/crates/ksp-config-lib/USAGE.md +++ b/crates/ksp-config-lib/USAGE.md @@ -1,5 +1,5 @@ - + # Utilisation de ksp-config-lib @@ -33,6 +33,22 @@ Les arguments compris par Config sont : `cfgpath` et `schemapath` ne sont jamais lus depuis JSON, `.env` ou une variable KSP : cette règle évite un bootstrap récursif. +### 1.1 Inventorier les fichiers enregistrés + +Le registre expose une vue read-only déterministe des descripteurs connus : + +```rust +for descriptor in registry.descriptors() { + let file_id = descriptor.file_id().as_str(); + let kind = descriptor.kind(); + let filename = descriptor.filename(); + let schema_file_id = descriptor.schema_file_id(); + let _ = (file_id, kind, filename, schema_file_id); +} +``` + +L'ordre est celui des `file_id`. La vue reflète les éventuels overrides `--filemap` déjà appliqués tout en conservant le kind et l'association de schema. Elle permet notamment à une application de management de construire sa liste de documents/schemas sans dupliquer le registre dans sa propre couche. + ## 2. Charger et valider un document connu Les consumers utilisent un `file_id` logique : diff --git a/crates/ksp-config-lib/src/registry.rs b/crates/ksp-config-lib/src/registry.rs index b133851..362b036 100644 --- a/crates/ksp-config-lib/src/registry.rs +++ b/crates/ksp-config-lib/src/registry.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/src/registry.rs -// version: 3 +// version: 4 /// Bootstrap argument used to replace a known Config filename mapping. pub const ARG_FILE_MAP: &str = "--filemap"; @@ -165,6 +165,13 @@ impl ConfigFileRegistry { return std::result::Result::Ok(registry); } + /// Iterates over all registered descriptors in deterministic logical `file_id` order. + /// + /// The returned view is read-only and reflects filename overrides already applied to this registry. + pub fn descriptors(&self) -> impl std::iter::Iterator + '_ { + return self.descriptors.values(); + } + /// Returns the descriptor associated with a known logical file identifier. pub fn descriptor(&self, file_id: &ConfigFileId) -> ksp_core_lib::Result<&ConfigFileDescriptor> { return match self.descriptors.get(file_id) { diff --git a/crates/ksp-config-lib/tests/public_api.rs b/crates/ksp-config-lib/tests/public_api.rs index b09d0b6..43f85fa 100644 --- a/crates/ksp-config-lib/tests/public_api.rs +++ b/crates/ksp-config-lib/tests/public_api.rs @@ -1,5 +1,5 @@ // file: crates/ksp-config-lib/tests/public_api.rs -// version: 10 +// version: 11 //! Integration tests for the public `ksp-config-lib` bootstrap, registry, JSON/profile/composite, environment-resolution, sensitivity, Logging-adapter and //! management contracts. @@ -74,6 +74,25 @@ fn logical_file_registry_is_available_from_crate_root() { } } +#[test] +fn registry_descriptor_inventory_is_available_from_crate_root() { + let registry = ksp_config_lib::ConfigFileRegistry::defaults(); + assert!(registry.is_ok(), "public registry should remain constructible: {registry:?}"); + if let std::result::Result::Ok(registry) = registry { + let descriptors: std::vec::Vec<&ksp_config_lib::ConfigFileDescriptor> = registry.descriptors().collect(); + assert_eq!(descriptors.len(), 3); + assert_eq!(descriptors[0].file_id().as_str(), ksp_config_lib::FILE_ID_STD_LOGGING); + assert_eq!(descriptors[0].kind(), ksp_config_lib::ConfigFileKind::Config); + assert_eq!(descriptors[1].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_COMPOSITE); + assert_eq!(descriptors[2].file_id().as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING); + let schema_file_id = descriptors[0].schema_file_id(); + assert!(schema_file_id.is_some(), "public descriptor inventory should preserve schema association"); + if let std::option::Option::Some(schema_file_id) = schema_file_id { + assert_eq!(schema_file_id.as_str(), ksp_config_lib::FILE_ID_SCHEMA_STD_LOGGING); + } + } +} + #[test] fn validated_json_document_engine_is_available_from_crate_root() { let workspace = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../.."); diff --git a/crates/ksp-config-lib/unit_tests/registry.rs b/crates/ksp-config-lib/unit_tests/registry.rs index e1f9bec..417b90a 100644 --- a/crates/ksp-config-lib/unit_tests/registry.rs +++ b/crates/ksp-config-lib/unit_tests/registry.rs @@ -1,5 +1,58 @@ // file: crates/ksp-config-lib/unit_tests/registry.rs -// version: 3 +// version: 4 + +#[test] +fn descriptors_expose_complete_registry_in_deterministic_file_id_order() { + let registry = super::ConfigFileRegistry::defaults(); + assert!(registry.is_ok(), "default registry should be valid: {registry:?}"); + if let std::result::Result::Ok(registry) = registry { + let descriptors: std::vec::Vec<&super::ConfigFileDescriptor> = registry.descriptors().collect(); + assert_eq!(descriptors.len(), 3); + assert_eq!(descriptors[0].file_id().as_str(), super::FILE_ID_STD_LOGGING); + assert_eq!(descriptors[0].kind(), super::ConfigFileKind::Config); + assert_eq!(descriptors[0].filename(), std::path::Path::new(super::DEFAULT_STD_LOGGING_FILENAME)); + let schema_file_id = descriptors[0].schema_file_id(); + assert!(schema_file_id.is_some(), "logging descriptor should expose its validation schema"); + if let std::option::Option::Some(schema_file_id) = schema_file_id { + assert_eq!(schema_file_id.as_str(), super::FILE_ID_SCHEMA_STD_LOGGING); + } + assert_eq!(descriptors[1].file_id().as_str(), super::FILE_ID_SCHEMA_COMPOSITE); + assert_eq!(descriptors[1].kind(), super::ConfigFileKind::Schema); + assert_eq!(descriptors[2].file_id().as_str(), super::FILE_ID_SCHEMA_STD_LOGGING); + assert_eq!(descriptors[2].kind(), super::ConfigFileKind::Schema); + } +} + +#[test] +fn descriptors_reflect_filename_overrides_without_changing_logical_metadata() { + let registry = super::ConfigFileRegistry::defaults(); + let file_id = super::ConfigFileId::new(super::FILE_ID_STD_LOGGING); + assert!(registry.is_ok(), "default registry should be valid: {registry:?}"); + assert!(file_id.is_ok(), "logging file_id should be valid: {file_id:?}"); + if let (std::result::Result::Ok(registry), std::result::Result::Ok(file_id)) = (registry, file_id) { + let overridden = registry.with_filename_override(&file_id, "profiles/desktop.logging.json"); + assert!(overridden.is_ok(), "filename override should remain valid: {overridden:?}"); + if let std::result::Result::Ok(overridden) = overridden { + let mut found: std::option::Option<&super::ConfigFileDescriptor> = std::option::Option::None; + for descriptor in overridden.descriptors() { + if descriptor.file_id() == &file_id { + found = std::option::Option::Some(descriptor); + } + } + assert!(found.is_some(), "public descriptor inventory should retain the overridden logging descriptor"); + if let std::option::Option::Some(descriptor) = found { + assert_eq!(descriptor.file_id(), &file_id); + assert_eq!(descriptor.kind(), super::ConfigFileKind::Config); + assert_eq!(descriptor.filename(), std::path::Path::new("profiles/desktop.logging.json")); + let schema_file_id = descriptor.schema_file_id(); + assert!(schema_file_id.is_some(), "filename override should preserve schema association"); + if let std::option::Option::Some(schema_file_id) = schema_file_id { + assert_eq!(schema_file_id.as_str(), super::FILE_ID_SCHEMA_STD_LOGGING); + } + } + } + } +} #[test] fn defaults_register_logging_document_and_schema_with_distinct_roots() { diff --git a/deltas/0.1.4/pre.002.md b/deltas/0.1.4/pre.002.md new file mode 100644 index 0000000..a52ea1f --- /dev/null +++ b/deltas/0.1.4/pre.002.md @@ -0,0 +1,194 @@ + + + +# Delta 0.1.4-pre.002 — inventaire public du registre Config + +## Base requise + +```text +0.1.4-pre.001-fix.003 +workspace.package.version = "0.1.4-pre.1" +``` + +Le plan `docs/plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md` est considéré comme validé dans sa révision issue de `pre.001-fix.003`. + +## Objectif + +Traiter la première lacune `ksp-config-lib` identifiée par `pre.001` avant la construction du shell desktop : permettre à un consumer de management d'inventorier les fichiers enregistrés dans `ConfigFileRegistry` sans maintenir une liste parallèle de `file_id` et sans obtenir de capacité de mutation supplémentaire. + +Cette tranche reste volontairement limitée à l'inventaire public du registre. La soumission/réparation d'un source candidat invalide reste réservée à `pre.003`. + +## Version Cargo + +Conformément à `VER-ID-009`, `workspace.package.version` passe de : + +```text +0.1.4-pre.1 +``` + +à : + +```text +0.1.4-pre.2 +``` + +L'identifiant de livraison est : + +```text +0.1.4-pre.002 +``` + +## 1. API publique du registre + +`ConfigFileRegistry` expose désormais : + +```rust +pub fn descriptors(&self) -> impl std::iter::Iterator + '_ +``` + +Le contrat est volontairement read-only : + +- aucun descripteur n'est copié dans une seconde structure propriétaire ; +- aucune mutation du registre n'est exposée ; +- l'itération reflète les éventuels overrides de filename déjà appliqués ; +- `file_id`, `kind` et association de schema restent ceux du descripteur enregistré ; +- l'ordre est déterministe et correspond à l'ordre logique des `ConfigFileId` porté par le `BTreeMap` interne. + +Avec le registre par défaut actuel, l'ordre est : + +```text +cfg.std.logging +schema.composite +schema.std.logging +``` + +L'API ne crée pas de DTO applicatif. `ksp-app-config-desk` pourra convertir ces descripteurs vers ses propres DTO Tauri dans sa frontière applicative. + +## 2. Tests unitaires + +`unit_tests/registry.rs` couvre maintenant explicitement : + +- l'inventaire complet du registre par défaut ; +- l'ordre déterministe par `file_id` ; +- le `ConfigFileKind` de chaque famille ; +- l'association `cfg.std.logging -> schema.std.logging` ; +- la conservation de ces métadonnées après un override de filename ; +- la visibilité du filename effectivement overridé depuis l'inventaire. + +Les tests existants de lookup, résolution de path, validation des mappings, doublons et associations de schema restent inchangés dans leur responsabilité. + +## 3. Test de surface publique + +`tests/public_api.rs` vérifie que le consumer externe peut appeler `ConfigFileRegistry::descriptors()` depuis la racine de crate et exploiter les `ConfigFileDescriptor` publics sans accès à une API interne. + +Le test couvre l'ordre et les métadonnées nécessaires au futur panneau Documents de Config Desk. + +## 4. Documentation Config + +`README.md` précise maintenant que le registre possède un inventaire public read-only ordonné par `file_id`. + +`USAGE.md` ajoute un exemple version-neutral montrant comment parcourir : + +- `file_id` ; +- `kind` ; +- filename courant ; +- schema associé éventuel. + +`TODO.md` distingue désormais les deux lacunes révélées par `0.1.4` : + +- inventaire public du registre : **traité par `pre.002`** ; +- réparation/persistence d'un source candidat par `file_id` connu : **reste à traiter dans `pre.003`**. + +## 5. Ownership et extensibilité + +Cette tranche conserve les frontières décidées : + +```text +ConfigFileRegistry + -> possède les descripteurs connus + -> expose leur inventaire read-only + +ksp-app-config-desk + -> consommera l'inventaire + -> construira ses DTO applicatifs + -> ne maintiendra pas de liste parallèle de file_id +``` + +L'ajout futur d'un nouveau descripteur au registre le rendra donc automatiquement découvrable par le shell de management, indépendamment de la présence ou non d'un éditeur spécialisé pour ce `file_id`. + +## Hors scope confirmé + +Cette tranche n'ajoute pas : + +- `ksp-app-config-desk` ; +- Tauri ou dépendance frontend ; +- DTO TS-RS ; +- API de modification arbitraire du registre ; +- API de réparation/persistence de source candidat ; +- nouveau document Config ou nouveau schema ; +- variable `.env` ; +- modification du runtime Logging. + +## Fichiers ajoutés + +```text +deltas/0.1.4/pre.002.md +``` + +## Fichiers modifiés + +| Fichier | Version précédente | Nouvelle version | +|------------------------------------------------|-------------------:|-----------------:| +| `Cargo.toml` | 62 | 63 | +| `crates/ksp-config-lib/src/registry.rs` | 3 | 4 | +| `crates/ksp-config-lib/unit_tests/registry.rs` | 3 | 4 | +| `crates/ksp-config-lib/tests/public_api.rs` | 10 | 11 | +| `crates/ksp-config-lib/README.md` | 1 | 2 | +| `crates/ksp-config-lib/USAGE.md` | 2 | 3 | +| `crates/ksp-config-lib/TODO.md` | 1 | 2 | + +## Fichiers supprimés + +Aucun. + +## Validations exécutées + +Dans l'environnement de préparation disponible : + +- contrôle statique du diff borné à l'inventaire du registre ; +- vérification de `workspace.package.version = "0.1.4-pre.2"` ; +- vérification des headers `file:` / `version:` des fichiers modifiés ; +- vérification de l'absence de `?`, `unwrap`, `expect`, `panic` et `unsafe` dans le nouveau code Rust ; +- vérification des lignes Rust modifiées vis-à-vis de la limite KSP de 160 colonnes ; +- vérification de la documentation publique de `ConfigFileRegistry::descriptors()` ; +- vérification que les tests couvrent ordre, kind, schema et override ; +- vérification syntaxique TOML du `Cargo.toml` avec le parseur disponible ; +- contrôle des fences Markdown et des espaces de fin de ligne dans les fichiers livrés. + +## Validations non exécutées + +Le sandbox de préparation ne fournit pas les binaires Rust/Cargo. Les validations obligatoires suivantes ne peuvent donc pas être exécutées ici : + +```text +cargo fmt --all +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-config-lib +cargo tree -p ksp-config-lib +``` + +Elles doivent être exécutées sur le workspace de développement après application du delta et avant validation/commit de `pre.002`. + +`cargo test --workspace` n'est pas requis pour cette tranche ciblée selon le plan de `0.1.4`; il reste réservé aux frontières globales justifiées et à la clôture de la release. + +## Décisions prises + +- l'inventaire reste une vue du registre existant, pas une collection dupliquée ; +- l'ordre public est déterministe par `file_id` ; +- les overrides restent visibles sans altérer l'identité logique et les associations de schema ; +- aucun DTO Config spécifique au desktop n'entre dans `ksp-config-lib` ; +- `pre.003` reste la tranche dédiée à la réparation validée/persistée d'un source candidat. + +## Questions ouvertes + +Aucune question bloquante pour `pre.002`.