# Delta 0.1.3-pre.012 ## Base requise Livraison précédente validée : ```text 0.1.3-pre.011-fix.001 ``` Version technique de cette base : ```text workspace.package.version = "0.1.3-pre.11.fix.1" Cargo.toml header version = 55 ``` Validations utilisateur exécutées le 2026-08-16 : ```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 -d OK, doublon transitif syn 2/3 déjà connu cargo tree -p ksp-logging-lib -d OK, aucun doublon ``` `cargo test --workspace` confirme notamment 61 tests unitaires + 9 tests publics pour `ksp-config-lib`. ## Objet de pre.012 Construire la première frontière runtime complète possédée par Config : ```text cfg.std.logging -> JSON + schema + invariants source -> profil sélectionné -> process > .env > fallback -> real/safe/sensitivity/provenance -> validation effective -> ksp_logging_lib::LoggingSettings ``` Cette tranche ne modifie pas encore les documents Config et ne persiste rien. ## `ResolvedLoggingConfig` Nouveau contrat public : ```text ResolvedLoggingConfig ``` Il conserve : ```text file_id source_path profile_id selection_source effective ResolvedConfigJson logs_directory résolu LoggingSettings ``` Son `Debug` manuel n'affiche pas directement `LoggingSettings` ni le root réel. Il s'appuie sur `ResolvedConfigJson::Debug`, donc sur l'arbre sûr/redacted. Les consumers légitimes peuvent obtenir : ```text settings() into_settings() logs_directory() effective() ``` Le `LoggingGuard` n'est jamais stocké par Config : il reste détenu par l'orchestration qui appelle `ksp_logging_lib::initialize/reinitialize`. ## Entrée de l'adapter `ConfigDocumentEngine` ajoute : ```text load_resolved_logging_config(requested_profile, environment) ``` La méthode : 1. charge `cfg.std.logging` ; 2. applique le profil par défaut ou le profil explicite ; 3. résout les placeholders avec le snapshot `ConfigEnvironment` ; 4. conserve la vue réelle/sûre et la provenance ; 5. valide la configuration effective ; 6. mappe les valeurs vers les contrats publics `ksp_logging_lib::*` ; 7. exécute enfin `LoggingSettings::validate()`. ## Mapping Logging Le mapping couvre explicitement : ```text LogFilterLevel SpanEvents ConsoleOutput LogFormat FileRotation OutputFilter TargetFilter ConsoleSettings FileSettings[] LoggingSettings ``` Le document commité `local_dev` doit donc produire les deux sinks fichier déjà déclarés et leurs filtres `level/target/domain`, ainsi que les deux overrides globaux de target. ## `logs_directory` Après interpolation : - un chemin absolu est conservé ; - un chemin relatif est ancré sur le current working directory du processus au moment de l'adaptation ; - un root inexistant est accepté : Logging créera les répertoires requis lors de l'initialisation des appenders ; - un root existant qui n'est pas un directory est rejeté ; - une erreur filesystem autre que `NotFound` pendant l'inspection est rejetée. Le fallback `${KSP_LOGS_DIRECTORY:-logs}` s'applique uniquement si `KSP_LOGS_DIRECTORY` est absent. Une valeur explicitement présente mais vide : ```text KSP_LOGS_DIRECTORY= ``` reste une valeur présente et produit : ```text config.effective_config_invalid ``` Elle ne retombe jamais silencieusement sur `logs`. ## Chemins des sinks Les `files[].path` restent relatifs sous `logs_directory`. L'invariant est désormais contrôlé deux fois : 1. sur le document source ; 2. après interpolation environnementale. La seconde validation empêche par exemple une valeur environnementale de transformer dynamiquement un path relatif en : ```text ../outside.log /var/log/outside.log ``` L'adapter sépare ensuite le path relatif en : ```text directory relatif file-name prefix ``` puis construit `FileSettings` sous le root Logging résolu. ## Frontière secrets Le document standard Logging n'a aucun besoin fonctionnel de secret. L'adapter refuse donc toute configuration effective dont `ResolvedConfigJson::sensitivity()` est `Secret`. Cette règle évite de transmettre une vraie valeur secrète à `LoggingSettings`, puis potentiellement à des diagnostics filesystem de `ksp-logging-lib`. Les erreurs finales de `LoggingSettings::validate()` sont encapsulées dans `config.effective_config_invalid` avec seulement : ```text logging_error_domain logging_error_code ``` Les contextes internes de l'erreur Logging ne sont pas recopiés par Config. ## Démonstration runtime Un test Config utilise le document commité, un root temporaire et le vrai runtime Logging afin de démontrer : ```text Config -> LoggingSettings -> initialize -> reinitialize ``` Le test vérifie aussi que l'initialisation des appenders crée les sous-répertoires configurés lorsqu'ils n'existent pas, puis recharge une configuration sans outputs avant cleanup. ## Diagnostics et erreurs Nouveau code stable : ```text config.effective_config_invalid ``` Il distingue une source JSON/schema valide d'une configuration devenue invalide après environnement/adaptation runtime. Les diagnostics Config de paths utilisent une représentation sûre lorsque la valeur pourrait provenir d'un resolver détaillé. ## Règles documentaires Deux règles KSP deviennent durables : ```text KSP-CONFIG-012 KSP-CONFIG-013 ``` Elles fixent respectivement : - la sémantique absolu/relatif/CWD/fallback de `logs_directory` ; - l'interdiction de secrets dans le standard Logging effectif. `FILE_CONTRACTS.md` enregistre également la revalidation post-interpolation de `files[].path`. ## `.env.example` Aucune nouvelle variable runtime n'est introduite. `.env.example` reste inchangé : ```text KSP_LOGS_DIRECTORY=logs ``` ## Dépendances Aucune nouvelle dépendance Cargo. La direction reste : ```text ksp-config-lib -> ksp-logging-lib ksp-logging-lib -X-> ksp-config-lib ``` ## Tests ajoutés Le nouveau module `unit_tests/logging.rs` couvre notamment : - mapping complet du profil `local_dev` ; - root relatif ancré au CWD ; - root absolu conservé ; - valeur explicite vide rejetée sans fallback ; - root existant non-directory rejeté ; - paths fichier effectifs sans escape ; - frontière Secret de Logging et canary sans fuite ; - `Debug` de `ResolvedLoggingConfig` ; - `initialize/reinitialize` réel et création des répertoires de sinks. La surface publique ajoute un test d'adressabilité de `ResolvedLoggingConfig`, de la méthode adapter et du nouveau code d'erreur. Après ajout, la crate contient 70 tests unitaires Config et 10 tests publics à exécuter chez l'utilisateur. ## Fichiers ajoutés ```text crates/ksp-config-lib/src/logging.rs crates/ksp-config-lib/unit_tests/logging.rs deltas/0.1.3/pre.012.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-config-lib/src/environment.rs crates/ksp-config-lib/src/error.rs crates/ksp-config-lib/src/lib.rs crates/ksp-config-lib/tests/public_api.rs docs/rules/RULES_KSP.md docs/rules/FILE_CONTRACTS.md docs/plans/000-README.md docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md ``` ## Hors scope Toujours hors `pre.012` : - mutation/persistence JSON ; - create/update/remove `.env` ; - reveal secret de management ; - application desktop Config ; - watcher/reload automatique de Config ; - autres documents standard Store/Wallet/Transport. Ces sujets commencent avec `pre.013` ou les releases prévues ultérieurement. ## Validation demandée ```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 cargo tree -p ksp-logging-lib -d ``` Aucune validation Cargo locale n'est revendiquée dans l'environnement de génération de ce delta.