# Delta 0.1.3-pre.013 ## Base requise Livraison précédente validée : ```text 0.1.3-pre.012 ``` Version technique de cette base : ```text workspace.package.version = "0.1.3-pre.12" Cargo.toml header version = 56 ``` 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-config-lib -e features OK cargo tree -p ksp-logging-lib -d OK, aucun doublon ``` `cargo test --workspace` confirme notamment 70 tests unitaires + 10 tests publics pour `ksp-config-lib` et 34 tests unitaires Logging avec toutes ses intégrations vertes. ## Objet de pre.013 Fermer la première surface de management/persistence Config sans introduire Tauri ni permettre aux applications de contourner `ksp-config-lib` : ```text registered file_id -> management source read -> typed std.logging mutation -> candidate validation -> atomic persistence process env (read-only) + .env (read/write) -> desired/effective/shadow report -> explicit reveal when UI management intentionally needs the real value ``` ## `ConfigManagement` Nouveau contrat public : ```text ConfigManagement ``` Il possède un `ConfigDocumentEngine` et utilise par défaut le `.env` conventionnel : ```text ./.env ``` Il n'ajoute aucun path runtime Config supplémentaire et ne modifie jamais l'environnement hérité du processus. L'authentification/autorisation de l'utilisateur final reste une responsabilité de la future application `ksp-app-config-desk`. Config fournit une frontière explicite qui évite l'exposition accidentelle mais ne prétend pas être un système d'authentification intra-processus. ## Lecture management `ConfigManagement::read_source(file_id)` lit le texte brut d'un document **Config enregistré** par son `file_id`. Cette lecture : - ne prend jamais un path arbitraire fourni par le caller ; - refuse un `file_id` de kind Schema ; - reste possible lorsque le document est syntaxiquement/schema/sémantiquement invalide, afin qu'une UI de management puisse afficher et corriger sa source ; - retourne `ConfigManagedSource`, dont `Debug` n'expose pas le contenu brut. Aucune primitive publique générique « save raw JSON to path » n'est ajoutée. ## Mutation typée de `std.logging.json` Nouveaux contrats source publics : ```text LoggingConfigDocument LoggingProfileConfig LoggingConsoleConfig LoggingFileConfig LoggingOutputFilterConfig LoggingTargetFilterConfig ``` Ils représentent la forme source de `cfg.std.logging` et permettent une mutation structurée en mémoire. La persistance suit obligatoirement : ```text LoggingConfigDocument -> serde_json candidate -> registered std.logging schema -> KSP profile/logging semantic invariants -> pretty JSON + newline final -> atomic commit ``` Un candidate invalide retourne l'erreur de validation existante et ne touche pas au fichier destination. `ConfigDocumentEngine` reçoit uniquement un helper interne `validate_candidate(...)`; la validation reste possédée par Config et n'est pas dupliquée dans la couche management. ## Persistence atomique Nouveau module privé : ```text src/persistence.rs ``` Stratégie : 1. créer un fichier temporaire avec `create_new` dans le même répertoire que la destination ; 2. appliquer les permissions requises ; 3. écrire tout le contenu ; 4. `sync_all` le fichier temporaire ; 5. fermer le handle ; 6. remplacer la destination par `rename` ; 7. nettoyer le temporaire si une étape pré-commit échoue. La destination reste donc l'ancien fichier complet jusqu'au commit final. Les permissions du fichier existant sont conservées. Sur Unix, un nouveau `.env` créé par Config reçoit explicitement : ```text 0600 ``` Les documents JSON ne reçoivent pas artificiellement ce mode privé ; un fichier existant conserve son mode. Nouveau code d'erreur : ```text config.persistence_write_failed ``` ## Management du `.env` Nouvelles opérations : ```text set_dotenv_value(name, value) remove_dotenv_value(name) reveal_dotenv_value(name) reveal_effective_environment_value(name) environment_report() ``` Mutation autorisée uniquement pour les namespaces déjà possédés par Config : ```text KSP_* KSPB_* ``` Une mutation ne touche jamais `std::env::set_var/remove_var` et ne prétend donc jamais modifier le shell parent, systemd, Docker/Kubernetes ou l'environnement déjà hérité du processus. Avant mutation, le `.env` existant doit être interprétable par la grammaire Config actuelle. Un `.env` invalide est refusé sans altération. L'éditeur ciblé : - conserve les lignes/commentaires non concernés ; - remplace uniquement l'assignment ciblé ; - encode les valeurs nécessitant espaces, `#`, quotes, backslash ou contrôles avec la forme double-quoted déjà comprise par Config ; - normalise un fichier modifié avec newline final ; - ne réécrit pas un assignment si la valeur persistée est déjà identique ; - ne crée pas le fichier lors d'un remove d'une clé absente. ## Desired / effective / shadow `ConfigEnvironmentReport` n'embarque aucune valeur réelle secrète. Il expose : ```text variable_name sensitivity desired_safe_value # valeur .env persistée effective_safe_value # process sinon .env effective_source shadowed_by_process_environment ``` Une entrée `.env` est `desired`; la valeur héritée du process reste prioritaire et peut donc la shadow. `ConfigEnvironmentChangeReport` expose après create/update/remove : ```text source_changed effective_changed shadowed_by_process_environment reload_required ``` Si le process shadow une modification `.env`, `source_changed = true` mais `effective_changed = false` et `reload_required = false` pour le processus courant. ## Reveal explicite et secrets Les rapports management ordinaires utilisent la représentation sûre : ```text KSP_SECRET_* / KSPB_SECRET_* -> ******** ``` La valeur réelle n'est accessible qu'en appelant explicitement : ```text reveal_dotenv_value(...) reveal_effective_environment_value(...) ``` Ces méthodes sont destinées à une surface UI management légitimement autorisée. Elles ne changent pas les règles suivantes : - jamais de secret réel dans `Debug` ; - jamais de secret réel dans les logs ; - jamais de secret réel dans les diagnostics génériques ; - l'application reste propriétaire de l'autorisation utilisateur. ## Règles durables Ajout de : ```text KSP-CONFIG-014 KSP-CONFIG-015 KSP-CONFIG-016 ``` pour figer respectivement : - la persistence validée/atomique bornée aux ressources Config connues ; - la distinction process read-only / `.env` read-write et le reporting shadow ; - la séparation report sûr / reveal explicite des valeurs sensibles. `FILE_CONTRACTS.md` documente également la stratégie de persistence, le newline JSON, la preservation des permissions et le mode `0600` d'un nouveau `.env` sur Unix. ## `.env.example` Aucune nouvelle variable runtime n'est introduite par cette tranche. `.env.example` reste donc inchangé : ```text KSP_LOGS_DIRECTORY=logs ``` Les variables utilisées uniquement comme canaries/tests ne font pas partie de l'inventaire runtime. ## Dépendances Aucune nouvelle dépendance Cargo. La direction reste : ```text ksp-config-lib -> ksp-core-lib ksp-config-lib -> ksp-logging-lib ksp-logging-lib -X-> ksp-config-lib ``` ## Tests ajoutés Le nouveau module `unit_tests/management.rs` ajoute 10 tests couvrant notamment : - lecture raw d'un source schema-invalide ; - mutation typée + persistance + reload de `std.logging.json` ; - candidate Logging invalide sans altération du fichier ; - save identique sans reload ; - create/update/remove `.env` ; - quoting et preservation de commentaires/lignes externes ; - `.env` invalide non modifié ; - namespace externe refusé sans création de `.env` ; - report secret redacted + reveal explicite du canary ; - process shadowing desired `.env` sans faux changement effectif ; - mode `0600` du nouveau `.env` sur Unix. La surface publique ajoute un test d'adressabilité des contrats management. Après ajout, `ksp-config-lib` doit compter : ```text 80 tests unitaires 11 tests publics ``` à exécuter chez l'utilisateur. ## Fichiers ajoutés ```text crates/ksp-config-lib/src/management.rs crates/ksp-config-lib/src/persistence.rs crates/ksp-config-lib/unit_tests/management.rs deltas/0.1.3/pre.013.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-config-lib/src/document.rs 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.013` : - application desktop Config/Tauri ; - watcher automatique de fichiers ; - rechargement automatique du runtime après save ; - mutation générique de documents arbitraires ; - management d'un environnement parent/systemd/container ; - autres documents standard Store/Wallet/Transport ; - audit global empêchant tous les futurs contournements Config hors crate, prévu en `pre.014`. ## 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.