# Delta 0.1.3-pre.009 ## Base requise Livraison précédente validée : ```text 0.1.3-pre.008 ``` Version technique de cette base : ```text workspace.package.version = "0.1.3-pre.8" Cargo.toml header version = 49 ``` Validations utilisateur exécutées le 2026-08-15 : ```text cargo fmt --all OK cargo check --workspace OK cargo clippy --workspace --all-targets OK cargo test --workspace OK cargo tree -p ksp-config-lib OK cargo tree -p ksp-config-lib -e features OK ``` `cargo test --workspace` confirme notamment 33 tests unitaires + 6 tests publics pour `ksp-config-lib`. `cargo tree -p ksp-config-lib -d` ne signale que la coexistence transitive déjà connue `syn 2.0.119` / `syn 3.0.3` portée par l'écosystème `jsonschema`; aucune correction de dépendance KSP n'est justifiée dans cette tranche. ## Objet de pre.009 Introduire le contrat de composition générique avant la résolution environnement : ```text composite file_id -> schema.composite -> composite profile -> document references by file_id -> default or composite-selected document profile -> ResolvedConfigProfile per component -> preserve Global/Profile provenance ``` Aucun composite runtime d'application fictif n'est créé. ## `schema.composite` Le registre Config connaît désormais : ```text schema.composite -> composite.schema.json ``` Le mapping est résolu sous `schemapath` et peut être remplacé comme les autres fichiers connus : ```text --filemap=schema.composite=my.composite.schema.json ``` En revanche, le registre par défaut n'introduit aucun : ```text cfg.composite. ``` Un tel descriptor sera ajouté seulement lorsqu'un consumer concret existera. ## Contrat composite Le schema générique versionné est : ```text config/schemas/composite.schema.json ``` Un exemple non runtime est fourni sous : ```text config/examples/composite.example.json ``` Structure : ```text format_version default_profile profiles[] profile_id documents[] component_id file_id profile_id? # optionnel ``` Règles : - le composite utilise le même modèle `default_profile` / `profiles` que les documents standards ; - `component_id` est unique à l'intérieur d'un profil composite ; - une référence cible exclusivement un `cfg.std.*` connu du registre ; - une référence ne contient jamais de filename physique ; - l'imbrication de composites n'est pas ouverte dans cette première surface ; - `profile_id` absent conserve le `default_profile` autonome du document référencé ; - `profile_id` présent impose ce profil depuis la composition. ## Résolution publique `ConfigDocumentEngine` expose maintenant : ```text load_resolved_composite(file_id, requested_profile) ``` Le caller peut sélectionner : ```text None -> default_profile du composite Some(profile_id) -> profil composite explicite ``` Le résultat `ResolvedConfigComposite` conserve : ```text file_id du composite path source profile_id composite sélectionné selection_source components par component_id ``` Chaque `ResolvedCompositeComponent` conserve le `ResolvedConfigProfile` du document standard référencé. Ainsi les informations déjà stabilisées en `pre.008` restent disponibles : ```text globals profile effective origin(key) = Global | Profile ``` ## Provenance de sélection `ConfigProfileSelectionSource` possède désormais : ```text DefaultProfile Explicit Composite ``` Lorsqu'un composite déclare explicitement : ```json { "file_id": "cfg.std.logging", "profile_id": "local_dev" } ``` le `ResolvedConfigProfile` correspondant porte : ```text selection_source = Composite ``` Si `profile_id` est absent, le document référencé conserve : ```text selection_source = DefaultProfile ``` La provenance `Global/Profile` de chaque valeur top-level n'est pas remplacée par cette provenance de sélection. ## Validation sémantique Un composite enregistré est soumis à : 1. JSON syntax ; 2. `schema.composite` ; 3. contrat générique `default_profile` / `profiles` ; 4. unicité des `component_id` par profil ; 5. validité et enregistrement des `file_id` référencés ; 6. restriction aux documents standards `cfg.std.*` ; 7. validation/résolution du profil référencé, y compris le `default_profile` lorsqu'aucun override n'est fourni. Un document référencé invalide ou inconnu utilise le nouveau diagnostic : ```text config.composite_reference_invalid ``` Un profil document ou composite demandé mais absent conserve : ```text config.profile_not_found ``` ## Tests Les nouveaux tests couvrent notamment : - enregistrement de `schema.composite` sans composite runtime fictif ; - validation du schema/example composite versionné ; - résolution du profil composite par défaut ; - utilisation du `default_profile` du document référencé ; - sélection explicite d'un profil composite ; - provenance `Composite` lorsqu'un profil documentaire est imposé par le composite ; - profil composite inconnu ; - référence vers un `file_id` standard inconnu ; - duplication de `component_id` dans un profil composite ; - disponibilité des constantes/schema/provenance depuis le crate-root. Les tests de résolution utilisent un descriptor composite privé à la crate pointant vers l'exemple versionné ; il ne fait pas partie de `ConfigFileRegistry::defaults()`. ## Hors scope Cette tranche n'introduit pas encore : - composite runtime d'une application réelle ; - `.env` ; - lecture de l'environnement du processus ; - interpolation `${NAME}` / `${NAME:-fallback}` ; - `Public/Internal/Secret` ; - redaction ; - adaptation vers `ksp_logging_lib::LoggingSettings` ; - mutation/persistence. ## Dépendances Aucune dépendance externe ou feature Cargo supplémentaire n'est ajoutée. `ksp-config-lib` ne dépend toujours pas de `ksp-logging-lib` dans cette tranche. ## Version technique La prerelease devient : ```text workspace.package.version = "0.1.3-pre.9" Cargo.toml header version = 50 ``` ## Fichiers ajoutés ```text config/examples/composite.example.json config/schemas/composite.schema.json crates/ksp-config-lib/src/composite.rs crates/ksp-config-lib/unit_tests/composite.rs deltas/0.1.3/pre.009.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-config-lib/src/document.rs crates/ksp-config-lib/src/error.rs crates/ksp-config-lib/src/lib.rs crates/ksp-config-lib/src/profile.rs crates/ksp-config-lib/src/registry.rs crates/ksp-config-lib/tests/public_api.rs crates/ksp-config-lib/unit_tests/registry.rs docs/plans/000-README.md docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md docs/rules/FILE_CONTRACTS.md ``` ## Fichiers supprimés Aucun. ## Contrôles exécutés dans l'environnement de génération - parsing JSON du schema et de l'exemple composite ; - validation du schema Draft 2020-12 et de l'exemple avec l'implémentation JSON Schema disponible dans l'environnement ; - comparaison du delta avec la base `pre.008` ; - contrôle des headers/version modifiés ; - contrôle de l'absence de nouvelle dépendance Cargo ; - contrôle statique des interdictions `unsafe`, `unwrap`, `expect`, `panic`, opérateur `?` et accès environnement applicatif dans les nouveaux sources de production ; - contrôle de la composition exacte de l'archive delta ; - réapplication du delta sur une copie de `pre.008` pour vérifier la reproduction de l'arbre livré. `cargo`, `rustc` et `rustfmt` ne sont pas disponibles dans l'environnement de génération. Aucune validation Rust n'est déclarée réussie ici. ## Validations utilisateur à exécuter ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test --workspace cargo tree -p ksp-config-lib cargo tree -p ksp-config-lib -d cargo tree -p ksp-config-lib -e features ``` Après validation de `pre.009`, la prochaine tranche planifiée est : ```text 0.1.3-pre.010 — .env + process env + resolver ${...} ```