From 5cba2beb648812758aaead118b75944390be2220 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Sat, 15 Aug 2026 01:47:06 +0200 Subject: [PATCH] v0.1.3-pre.001-fix.001 --- deltas/0.1.3/pre.001-fix.001.md | 273 +++ docs/plans/000-README.md | 4 +- docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md | 10 +- .../005-V0_1_3_CONFIG_FOUNDATION_PLAN.md | 1668 +++++++++-------- 4 files changed, 1195 insertions(+), 760 deletions(-) create mode 100644 deltas/0.1.3/pre.001-fix.001.md diff --git a/deltas/0.1.3/pre.001-fix.001.md b/deltas/0.1.3/pre.001-fix.001.md new file mode 100644 index 0000000..739668e --- /dev/null +++ b/deltas/0.1.3/pre.001-fix.001.md @@ -0,0 +1,273 @@ + + + +# Delta 0.1.3-pre.001-fix.001 + +## Base requise + +Livraison précédente : + +```text +0.1.3-pre.001 +``` + +Ce correctif reste documentaire. Il corrige le plan de `pre.001` avant tout développement fonctionnel de `ksp-config-lib` et ne réécrit pas le delta historique `pre.001.md`. + +## Objectif + +Aligner le plan Config sur le contrat fonctionnel validé après `pre.001` : + +- `ksp-config-lib` devient l'unique propriétaire KSP de la lecture/résolution/validation/mutation de la configuration applicative ; +- les variables applicatives sont résolues par Config depuis l'environnement réel du processus et un `.env` conventionnel ; +- la priorité est `process env > .env > fallback` ; +- les fallbacks sont déclarés au point d'usage par `${NAME:-fallback}` ; +- les références `${KSP_*}` / `${KSPB_*}` dans les documents JSON sont elles-mêmes les déclarations d'usage, sans table de bindings centrale ; +- les valeurs dérivées de `*_SECRET_*` conservent une valeur runtime réelle et une représentation sûre/redacted ; +- les variables absentes sans fallback produisent diagnostic + warning et empêchent une résolution runtime complète ; +- Config peut créer/modifier/supprimer les entrées du `.env` ; +- la première surface réelle est renommée `config/std.logging.json` ; +- les futurs documents et composites suivent `std..json` et `composite..json`. + +Aucune implémentation `pre.002` ne doit commencer avant validation utilisateur du plan corrigé. + +## Corrections apportées au plan + +### `.env` conventionnel + +La décision initiale : + +```text +config/environment.env +``` + +est annulée. + +La source persistante locale par défaut devient : + +```text +.env +``` + +à la racine runtime/workspace fournie à Config. + +Le fichier reste ignoré par Git et peut être manipulé exclusivement via `ksp-config-lib` dans l'écosystème KSP. + +### Priorité des variables + +Pour une variable utilisée : + +```text +process environment +> .env +> fallback déclaré au point d'usage +> missing +``` + +Exemple : + +```text +export KSP_PUBLIC_FOO=console +.env: KSP_PUBLIC_FOO=dotenv +JSON: ${KSP_PUBLIC_FOO:-fallback} +``` + +La valeur effective est `console`. + +Une chaîne vide explicitement définie est considérée comme définie et ne déclenche pas le fallback. + +### Placeholders Config + +Le rejet initial de l'interpolation `${...}` est annulé. + +Les syntaxes initiales sont : + +```text +${KSP_VAR} +${KSP_VAR:-fallback} +``` + +et leurs équivalents `KSPB_*`. + +Le resolver appartient à Config et conserve provenance/sensibilité. Il n'est pas délégué à un consumer ni à une expansion dotenv opaque. + +### Suppression des bindings statiques + +La table prédéfinie : + +```text +clé Config -> nom de variable +``` + +n'est plus retenue. + +Une référence comme : + +```json +"logs_directory": "${KSP_LOGS_DIRECTORY:-logs}" +``` + +constitue directement la déclaration d'usage de `KSP_LOGS_DIRECTORY`. + +Config peut aussi exposer une requête directe nom + fallback optionnel pour les rares variables utilisées hors document JSON, toujours sans accès `std::env` direct dans les consumers. + +### Missing sans fallback + +Lorsqu'une référence `${KSP_VAR}` n'est définie ni dans le process ni dans `.env` : + +- Config produit un diagnostic structuré ; +- Config émet un warning sous le target `ksp-config-lib` lorsque Logging est disponible ; +- le diagnostic indique nom/document/path mais aucune valeur secrète ; +- la construction d'un runtime complet échoue tant que la référence reste non résolue ; +- une application de management peut néanmoins charger le document source pour le corriger. + +### Secrets et valeurs composées + +Une chaîne telle que : + +```text +https://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY} +``` + +doit conserver conceptuellement : + +```text +real = https://mainnet.helius-rpc.com/?api-key= +safe = https://mainnet.helius-rpc.com/?api-key=******** +sensitivity = Secret +provenance = variable + source effective +``` + +Le runtime légitime peut utiliser `real`; les logs/diagnostics utilisent `safe`. + +Une application de management Config peut explicitement révéler/modifier un secret. Cette exception de visualisation n'autorise jamais le secret dans les logs. + +### Nomenclature des documents + +La première surface réelle devient : + +```text +config/std.logging.json +config/schemas/std.logging.schema.json +``` + +Nomenclature future : + +```text +config/std..json +config/composite..json +``` + +Exemple futur : + +```text +config/composite.ksp-app-wallet-desk.json +``` + +Les autres documents spécialisés ne sont pas créés avant leurs composants. + +### Globals, profils et composites + +Le contrat maintient : + +```text +paramètres globaux ++ default_profile ++ profiles +``` + +Une composition assemble les documents spécialisés et choisit éventuellement leurs profils sans recopier leur contenu. Les globals du document restent automatiquement partie de la configuration effective. + +### Mutation de l'environnement + +Le contrat distingue : + +- environnement réel du processus : source read-only et prioritaire ; +- `.env` : source persistante read/write possédée par Config. + +Config peut créer/modifier/supprimer des entrées `.env` et doit signaler si une valeur process continue à shadow la valeur persistée. + +Il ne prétend pas modifier le shell parent, systemd, Docker ou un autre processus. + +## Découpage prerelease corrigé + +```text +pre.002 fondation crate + contrats source +pre.003 JSON Schema + config/std.logging.json +pre.004 profils + composition +pre.005 .env + resolver ${...} + fallback + warnings missing +pre.006 sensibilité + real/safe + Logging adapter +pre.007 management + persistence JSON/.env +pre.008 ownership audits + robustesse +pre.009 clôture +``` + +Le périmètre `0.1.3` reste une release unique et `0.1.4` reste `ksp-app-config-desk`. + +## Fichiers ajoutés + +- `deltas/0.1.3/pre.001-fix.001.md` + +## Fichiers modifiés + +- `docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md` +- `docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md` +- `docs/plans/000-README.md` + +## Fichiers supprimés + +Aucun. + +## Version Cargo + +Aucune modification de `Cargo.toml`. + +Ce fix est uniquement documentaire et respecte `VER-ID-008`. La version workspace reste : + +```text +0.1.3-pre.1 +``` + +L'identifiant de livraison est : + +```text +0.1.3-pre.001-fix.001 +``` + +## Dépendances + +Aucune dépendance ajoutée ou modifiée. + +Le plan ne choisit pas encore de bibliothèque dotenv. Le choix sera audité au delta qui implémente réellement `.env`. + +## Validations exécutées + +- comparaison de la livraison `0.1.3-pre.001` avec la base `v0.1.2` ; +- relecture de `docs/rules/VERSION_WORKFLOW.md`, notamment `VER-ID-008` et `VER-ARCHIVE-004` ; +- réaudit ciblé de la référence bot3 pour `.env`, `${NAME:-fallback}`, secrets composés et composition ; +- contrôle des headers `file:` / `version:` des fichiers modifiés/ajoutés ; +- recherche des anciennes décisions `environment.env`, interdiction d'interpolation et bindings statiques dans le plan corrigé ; +- contrôle de la nomenclature `std.logging.json` / `std..json` / `composite..json` ; +- contrôle que le correctif ne modifie aucun code Rust, aucun manifest Cargo et aucun fichier runtime Config ; +- contrôle du contenu de l'archive delta selon `VER-ARCHIVE-004`. + +## Validations non exécutées + +Aucune validation Cargo n'est déclarée réussie dans ce correctif documentaire. + +Aucun code Config n'existe encore et aucun manifest/code Rust n'est modifié par le fix. Les validations Cargo de `0.1.3` commenceront avec les tranches de développement applicables. + +## Questions ouvertes avant `pre.002` + +Le plan corrigé est soumis à validation utilisateur. + +Les détails volontairement différés à l'implémentation sont : + +- bibliothèque dotenv éventuelle ou parser borné possédé par Config ; +- grammaire précise des quotes/escapes du `.env` ; +- type Rust exact de la valeur `real/safe/provenance/sensitivity` ; +- primitive exacte d'écriture atomique ; +- noms finaux des APIs runtime/diagnostic/management. + +Ces choix ne doivent pas modifier les invariants fonctionnels fixés par le plan. + +Après validation de ce fix, la prochaine tranche est `0.1.3-pre.002`. diff --git a/docs/plans/000-README.md b/docs/plans/000-README.md index 1fb4e73..b64f322 100644 --- a/docs/plans/000-README.md +++ b/docs/plans/000-README.md @@ -1,5 +1,5 @@ - + # Plans KSP @@ -13,7 +13,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou - [`002-FUNCTIONAL_RELEASE_SEQUENCE.md`](002-FUNCTIONAL_RELEASE_SEQUENCE.md) — séquence active de référence des premières releases fonctionnelles ; - [`003-V0_1_1_CORE_FOUNDATION_PLAN.md`](003-V0_1_1_CORE_FOUNDATION_PLAN.md) — plan historique clôturé de la release stable `0.1.1`, établi par `0.1.1-pre.001` puis consolidé jusqu'à `0.1.1-rel.001`. - [`004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`](004-V0_1_2_LOGGING_FOUNDATION_PLAN.md) — plan historique clôturé de la release stable `0.1.2`, établi par `0.1.2-pre.001` puis consolidé jusqu'à `0.1.2-rel.001`. -- [`005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](005-V0_1_3_CONFIG_FOUNDATION_PLAN.md) — plan actif de `0.1.3 — Configuration foundation`, établi par `0.1.3-pre.001` avant développement fonctionnel de `ksp-config-lib`. +- [`005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](005-V0_1_3_CONFIG_FOUNDATION_PLAN.md) — plan actif de `0.1.3 — Configuration foundation`, établi par `0.1.3-pre.001` puis corrigé par `pre.001-fix.001` avant développement fonctionnel de `ksp-config-lib`. Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre. diff --git a/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md b/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md index ea62efb..1a9ab20 100644 --- a/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md +++ b/docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md @@ -1,5 +1,5 @@ - + # Séquence des releases fonctionnelles KSP @@ -167,7 +167,7 @@ ksp-config-lib Introduire la configuration générale KSP. -Le `0.1.3-pre.001` a revalidé ce périmètre et décidé qu'il tient dans une seule release à condition de limiter le premier cycle au socle générique, au document Logging, à la composition, à l'environnement KSP/KSPB, aux surfaces d'accès et à la persistence autorisée. Le plan normatif détaillé est `docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`. +Le `0.1.3-pre.001`, corrigé par `pre.001-fix.001`, a revalidé ce périmètre et décidé qu'il tient dans une seule release à condition de limiter le premier cycle au socle générique, au document Logging, à la composition, à l'environnement KSP/KSPB, aux surfaces d'accès et à la persistence autorisée. Le plan normatif détaillé est `docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`. Périmètre retenu : @@ -178,9 +178,11 @@ Périmètre retenu : - résolution ; - validation ; - modification/sauvegarde ; -- variables d'environnement `KSP_*` / `KSPB_*` ; +- variables d'environnement `KSP_*` / `KSPB_*`, résolues exclusivement par Config ; +- priorité process env > `.env` > fallback `${NAME:-fallback}` ; +- propagation de la sensibilité et représentation sûre/redacted des valeurs dérivées de `*_SECRET_*` ; - secret/public/debug exposure policy ; -- `logging.config.json` séparé ; +- premier document spécialisé concret `config/std.logging.json` ; - vrais fichiers runtime sous `config/`, schemas sous `config/schemas/` et exemples sous `config/examples/` ; - documents unitaires spécialisés + fichiers composites par application/exécutable ; - ownership exclusif de `ksp-config-lib` sur lecture/résolution/validation/mutation des fichiers Config et variables d'environnement ; diff --git a/docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md b/docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md index 2ca2699..c4ba935 100644 --- a/docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md +++ b/docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md @@ -1,25 +1,44 @@ - + # Plan `0.1.3` — Configuration foundation ## 1. Statut et objectif -Ce plan est établi par `0.1.3-pre.001`, tranche obligatoire de brainstorming, audit et planification. +Ce plan a été établi par `0.1.3-pre.001`, puis corrigé par `0.1.3-pre.001-fix.001` avant tout développement fonctionnel de Config. -La base auditée est la release stable `v0.1.2`. La release `0.1.3` introduira `ksp-config-lib` comme frontière KSP unique pour : +La base auditée reste la release stable `v0.1.2`. -- les documents de configuration spécialisés ; +La release `0.1.3` introduira `ksp-config-lib` comme **propriétaire unique KSP de la configuration applicative**. À terme, les autres crates et applications KSP ne doivent pas : + +- lire directement les documents JSON de configuration ; +- valider elles-mêmes ces documents contre leurs schémas ; +- résoudre elles-mêmes les profils ou les compositions ; +- lire directement les variables applicatives `KSP_*` / `KSPB_*` par `std::env::*` ; +- charger directement le fichier `.env` ; +- interpréter elles-mêmes les expressions `${KSP_...}` ; +- écrire directement les documents Config ou le `.env` géré par KSP. + +Elles passent par les contrats publics de `ksp-config-lib`. + +`ksp-config-lib` doit fournir le moteur commun nécessaire à : + +- la lecture des documents spécialisés JSON ; +- la validation JSON Schema ; +- les paramètres globaux hors profils ; +- `default_profile` ; +- les profils ; - les compositions propres aux exécutables/applications ; -- la sélection et la résolution des profils ; -- la lecture des variables d'environnement KSP/KSPB et d'un fichier d'environnement géré par Config ; -- la validation syntaxique, structurelle, sémantique et effective ; -- la classification public/interne/secret ; -- les lectures runtime et management explicitement distinctes ; -- les mutations et persistences explicitement autorisées ; -- la construction de settings runtime appartenant à d'autres composants, en commençant par `ksp_logging_lib::LoggingSettings`. +- la lecture des variables provenant du processus et d'un `.env` ; +- la résolution des placeholders `${NAME}` et `${NAME:-fallback}` dans les valeurs de configuration ; +- la classification `Public` / `Internal` / `Secret` ; +- la conservation de la provenance et d'une représentation sûre/redacted des valeurs résolues ; +- les diagnostics de variables manquantes ; +- la manipulation et la persistence autorisées des documents JSON ; +- la création/modification/suppression des entrées du `.env` ; +- la construction des contrats runtime nécessaires aux consommateurs, en commençant par `ksp_logging_lib::LoggingSettings`. -`0.1.3-pre.001` ne crée pas encore `ksp-config-lib`, n'ajoute aucune dépendance fonctionnelle et ne crée aucun fichier runtime Config. Il fixe d'abord les contrats à implémenter. +`0.1.3-pre.001-fix.001` reste une tranche documentaire de conception. Il ne crée pas encore `ksp-config-lib`, ne crée aucun fichier runtime Config et n'ajoute aucune dépendance fonctionnelle. ## 2. Audit de la base stable `0.1.2` @@ -37,11 +56,11 @@ workspace.package.version = "0.1.2" edition = "2024" ``` -Aucune crate Config n'existe encore et aucun répertoire `config/` n'est présent dans la base stable fournie. +Aucune crate Config n'existe encore et aucun répertoire runtime `config/` n'est présent dans la base stable fournie. ### 2.1 Core disponible -`ksp-core-lib` fournit déjà les contrats nécessaires à Config : +`ksp-core-lib` fournit déjà : ```text ksp_core_lib::Error @@ -50,7 +69,7 @@ ksp_core_lib::ErrorContext ksp_core_lib::Result ``` -Les erreurs propres à Config resteront déclarées dans `ksp-config-lib` avec le domaine `config`. Core ne recevra aucune connaissance métier Config. +Les codes propres à Config restent possédés par `ksp-config-lib`, sous le domaine Config. Core ne reçoit aucune connaissance métier Config. ### 2.2 Logging disponible @@ -70,9 +89,9 @@ initialize(...) reinitialize(...) ``` -Config n'a donc aucune raison de redéfinir ces contrats. Il doit uniquement produire un `LoggingSettings` valide à partir de sa propre configuration effective. +Config ne redéfinit pas ces contrats. Il lit et résout sa configuration Logging, puis construit explicitement un `ksp_logging_lib::LoggingSettings`. -La direction reste : +La direction de dépendance reste : ```text ksp-config-lib -> ksp-core-lib @@ -89,185 +108,212 @@ Les règles actuelles imposent notamment : - `unsafe_code = "forbid"` ; - pas de `unwrap`, `expect`, `panic` ou `?` dans le code production ; - façade publique au crate-root, modules privés, pas de `mod.rs` ; -- tests unitaires sous `unit_tests/` autant que possible et tests d'intégration sous `tests/` ; -- toute dépendance externe centralisée dans `[workspace.dependencies]` ; -- aucune dépendance ajoutée avant un usage réel ; -- `ksp-logging-lib` reste l'unique propriétaire direct de `tracing`, `tracing-subscriber` et `tracing-appender`. +- tests unitaires hors `src` selon la convention du dépôt ; +- dépendances externes communes sous `[workspace.dependencies]` puis `.workspace = true` ; +- aucune dépendance ajoutée avant son usage réel ; +- `ksp-logging-lib` reste le seul propriétaire KSP direct de `tracing`, `tracing-subscriber` et `tracing-appender`. ## 3. Réaudit de la référence historique bot3 -L'archive `khadhroony-bot3` fournie contient une ancienne `ks-config` et les documents : +La référence historique bot3 utilisait déjà : -```text -logging.config.json -transport.config.json -listeners.config.json -store.config.json -wallet.config.json -execution.config.json -kb-app-demo-desktop.default.config.json -``` +- plusieurs documents spécialisés ; +- un `.env` à la racine ; +- des placeholders comme `${KS_LOGS_DIRECTORY:-logs}` ; +- des URLs composées contenant `${KS_SECRET_HELIUS_API_KEY}` ; +- des compositions applicatives ; +- une classification de sensibilité dérivée des placeholders. -Cette base est une référence historique, pas une source de vérité KSP. +Cette référence reste utile, mais KSP ne copie pas ses structures ni ses APIs aveuglément. -### 3.1 Principes conservés +### 3.1 Principes conservés et renforcés -Les éléments suivants restent pertinents : +KSP conserve : - documents spécialisés indépendants ; -- valeurs globales hors profils ; -- `default_profile` autonome dans chaque document spécialisé ; -- composition propre à un exécutable ; -- override de profil spécialisé depuis une composition ; -- schémas sous un répertoire dédié ; -- distinction source/runtime/public/diagnostic ; -- classification nominale des variables d'environnement ; -- propagation de la sensibilité la plus forte pour une valeur dérivée ; -- absence de TS-RS dans la bibliothèque Config lorsque le contrat est purement backend ; -- l'application Tauri possède ses DTO et ne sérialise pas aveuglément une configuration runtime complète. +- valeurs globales hors profils lorsqu'elles ne varient pas ; +- `default_profile` autonome ; +- composition propre à un exécutable/application ; +- sélection d'un profil spécialisé depuis la composition ; +- `.env` séparé des documents JSON ; +- priorité de l'environnement réel du processus sur `.env` ; +- fallback déclaré au point d'usage via `${NAME:-fallback}` ; +- classification nominale des variables ; +- propagation de la sensibilité la plus forte dans une valeur composée ; +- distinction entre valeur réelle et représentation diagnostic sûre ; +- DTO Tauri possédés par l'application et non par `ksp-config-lib`. -### 3.2 Éléments explicitement non repris +### 3.2 Corrections par rapport au plan `pre.001` initial -KSP ne reprend pas aveuglément : +Le plan initial de `pre.001` avait retenu à tort : -- le document runtime monolithique `AppConfig/ProfileConfig` historique ; -- les documents transport/listeners/store/wallet/execution avant l'existence des composants correspondants ; -- une section `application` opaque uniquement pour conserver un ancien runtime ; -- l'interpolation générique de chaînes `${NAME}` / `${NAME:-fallback}` dans n'importe quelle valeur JSON ; -- le chargement d'un fichier `.env` en modifiant globalement l'environnement du processus ; -- un modèle où une valeur effective secrète devient sérialisable puis est masquée après coup. +- `config/environment.env` au lieu d'un vrai `.env` ; +- une grammaire d'environnement KSP spéciale ; +- l'interdiction de l'interpolation `${...}` ; +- des bindings d'environnement prédéclarés clé Config -> variable ; +- une lecture limitée aux variables enregistrées par ces bindings. -La résolution d'environnement KSP sera au contraire fondée sur des bindings explicites entre une clé Config connue et un nom de variable d'environnement connu. +Ces décisions sont annulées. + +La règle corrigée est : + +> Une référence `${KSP_...}` ou `${KSPB_...}` présente dans une valeur JSON est elle-même une déclaration explicite d'usage de cette variable par le document. + +Config peut également exposer une API explicite de lecture d'une variable par nom avec fallback optionnel pour les rares usages qui ne proviennent pas d'un document JSON, mais les consumers ne lisent jamais directement `std::env`. ## 4. Décision de périmètre : `0.1.3` reste une seule release -Le périmètre peut rester dans `0.1.3` à condition de le borner strictement. +Le périmètre reste compatible avec une seule release si la première implémentation concrète reste bornée. -La première surface fonctionnelle contiendra : +La release construit le moteur générique nécessaire à : -1. l'infrastructure générique document/profil/composition ; -2. le seul document spécialisé actuellement justifié : Logging ; -3. l'environnement Config KSP/KSPB avec un fichier d'environnement géré ; -4. la classification et les surfaces runtime/diagnostic/management ; -5. la mutation/persistence du document Logging et du fichier d'environnement géré ; -6. l'adapter `ResolvedLoggingConfig -> ksp_logging_lib::LoggingSettings` ; -7. les tests/audits de propriété nécessaires. +1. documents JSON spécialisés ; +2. schémas ; +3. paramètres globaux ; +4. profils et `default_profile` ; +5. compositions ; +6. `.env` + environnement du processus ; +7. interpolation/fallback ; +8. provenance/sensibilité/redaction ; +9. mutation/persistence ; +10. adaptation Logging. -Ne sont pas créés dans `0.1.3` : Transport, Wallet, Store, Execution ou une configuration applicative générale fictive. +Mais le seul document spécialisé runtime créé et exercé concrètement en `0.1.3` est : -Cette limitation évite d'insérer une release supplémentaire avant `0.1.4`. La séquence reste donc : +```text +config/std.logging.json +``` + +Aucun `std.store.json`, `std.wallet.json`, `std.onchain-transport.json` ou autre fichier futur n'est créé prématurément. + +La séquence reste : ```text 0.1.3 ksp-config-lib 0.1.4 ksp-app-config-desk ``` -Si une tranche de mutation révèle une contrainte technique majeure non bornable, le plan pourra encore être corrigé par un delta ultérieur sans comprimer artificiellement la release. - ## 5. Matrice de responsabilités -| Responsabilité | Propriétaire | Consommateurs | Interdit | -|------------------------------------------|---------------------------|------------------------------------------------|-----------------------------------------------------------------| -| Lire les documents Config runtime | `ksp-config-lib` | apps/crates via API Config | lecture directe par les consumers | -| Lire l'environnement applicatif KSP/KSPB | `ksp-config-lib` | apps/crates via contrats Config | `std::env::*` applicatif hors Config | -| Résoudre composition/profils/overrides | `ksp-config-lib` | orchestration | résolution locale dans chaque binaire | -| Valider documents et valeurs effectives | `ksp-config-lib` | orchestration/management | validation divergente par consumer | -| Classer public/interne/secret | `ksp-config-lib` | runtime/management/app adapters | déduction ad hoc dans l'UI | -| Modifier/sauvegarder Config | `ksp-config-lib` | management explicite | écriture directe par l'application | -| Authentifier/autoriser un utilisateur UI | application/orchestration | `ksp-config-lib` reçoit une capacité explicite | prétendre que Config est un sandbox de sécurité intra-processus | -| Posséder `LoggingSettings` | `ksp-logging-lib` | Config construit ces settings | copie des types Logging dans Config | -| Posséder `LoggingGuard` | exécutable/application | lifecycle Logging | singleton Config global | -| Initialiser/recharger Logging | orchestration | Config fournit settings/changement | Logging lisant Config | -| DTO/bindings Tauri | application Tauri | frontend | TS-RS automatique dans Config | +| Responsabilité | Propriétaire | Consommateurs | Interdit | +|----------------------------------------------------------|--------------------------------------|------------------------------------|-----------------------------------------------------------| +| Lire un document Config JSON | `ksp-config-lib` | crates/apps via API Config | lecture directe par consumer | +| Valider JSON Schema | `ksp-config-lib` | orchestration/management | validation divergente dans chaque crate | +| Résoudre globals/profils/compositions | `ksp-config-lib` | orchestration | résolution locale dans un binaire | +| Lire `KSP_*` / `KSPB_*` du processus | `ksp-config-lib` | crates/apps via API Config | `std::env::var*` applicatif hors Config | +| Lire `.env` | `ksp-config-lib` | crates/apps via API Config | loader dotenv direct hors Config | +| Résoudre `${...}` et fallback | `ksp-config-lib` | tous les consumers | interpolation locale dans les consumers | +| Classer sensibilité et construire une valeur sûre | `ksp-config-lib` | runtime/logging/diagnostics | redaction ad hoc dans chaque crate | +| Modifier/sauvegarder JSON Config | `ksp-config-lib` | management explicite | écriture directe par application | +| Créer/modifier/supprimer une entrée `.env` | `ksp-config-lib` | management explicite | édition directe par application | +| Modifier l'environnement externe du shell/systemd/parent | propriétaire externe de ce processus | Config le lit seulement | prétendre qu'un child process peut administrer son parent | +| Posséder `LoggingSettings` | `ksp-logging-lib` | Config le construit | copie du type dans Config | +| Posséder `LoggingGuard` | orchestration/application | lifecycle Logging | singleton Config global | +| Initialiser/recharger Logging | orchestration | Config fournit settings/changement | Logging lisant Config | +| DTO/bindings Tauri | application Tauri | frontend | TS-RS automatique dans Config | -## 6. Arborescence et nomenclature retenues +## 6. Arborescence et nomenclature -### 6.1 Racine Config et fichiers runtime réels +### 6.1 Documents runtime -Les documents runtime réels appartiennent sous une racine Config explicite. Le layout workspace par défaut est : +Les vrais documents JSON runtime appartiennent sous : ```text config/ ``` -`ksp-config-lib` ne doit pas dépendre implicitement du current working directory pour ses opérations internes : une session/locator Config possède un `ConfigRoot`. Un helper workspace pourra construire `ConfigRoot = ./config`, tandis que les tests et applications installées peuvent fournir une autre racine explicite. - -Règles de chemin : - -- les documents gérés appartiennent sous `ConfigRoot` ; -- les chemins relatifs d'une composition sont résolus depuis le répertoire du composite puis normalisés ; -- après résolution, une source gérée ne peut pas sortir de `ConfigRoot` par `..` ou équivalent ; -- un chemin absolu n'est pas accepté dans un document composite ; -- `KSP_ENV_FILE` relatif est résolu depuis `ConfigRoot` et doit rester dans cette racine ; -- les APIs de test/management choisissent une autre racine plutôt que d'introduire une écriture arbitraire hors frontière Config. - -Pour la première surface : +Nomenclature retenue pour les documents spécialisés/unitaires : ```text -config/logging.config.json -config/environment.env +config/std..json ``` -`environment.env` est un fichier runtime local géré par Config et destiné notamment aux valeurs non versionnées/secrètes. Il devra être ignoré par Git lorsqu'il sera créé. Son absence est autorisée tant qu'aucune valeur requise n'en dépend. - -Ce fichier n'est **pas** défini comme un fichier dotenv générique. Il utilise une grammaire KSP versionnée et volontairement bornée afin d'éviter toute interpolation ou exécution implicite. La première ligne sémantique est l’en-tête de format réservé : +Premier fichier concret : ```text -# ksp-env-format: 1 +config/std.logging.json ``` -Le parser reconnaît cet en-tête avant le traitement des commentaires ordinaires ; il doit être présent exactement une fois et annoncer une version supportée. - -Grammaire initiale : - -- UTF-8 uniquement ; -- lignes vides autorisées ; -- après l’en-tête de format, commentaire uniquement lorsque le premier caractère non blanc est `#` ; -- affectation `NAME=VALUE` ; -- `NAME` respecte `[A-Z_][A-Z0-9_]*` puis doit appartenir à `KSP_*` ou `KSPB_*` ; -- une valeur non quotée est littérale après trim externe ; -- une valeur nécessitant espaces de bord, newline, guillemets ou escapes utilise une chaîne JSON entre doubles guillemets ; `serde_json` fournit alors l'encodage/décodage de la chaîne ; -- aucune expansion `$VAR`/`${VAR}`, aucune substitution shell, aucun `export`, aucune commande et aucune continuation implicite ; -- `#` après `=` appartient à la valeur, ce n'est pas un commentaire inline ; -- les doublons de nom sont refusés au lieu d'appliquer une règle first/last-wins ; -- les écritures Config produisent une forme canonique avec header de version, noms triés et valeurs encodées comme chaînes JSON. - -Les commentaires libres d'un fichier édité manuellement ne font pas partie du contrat de conservation lors d'une sauvegarde management : la conservation est sémantique, pas byte-for-byte. - -### 6.2 Schémas +Exemples futurs, uniquement lorsqu'ils deviennent nécessaires : ```text -config/schemas/logging.config.schema.json -config/schemas/composition.config.schema.json +config/std.store.json +config/std.wallet.json +config/std.onchain-transport.json ``` -Les schémas utilisent JSON Schema draft 2020-12. Ils sont auto-contenus dans la première surface : pas de résolution HTTP et pas de `$ref` externe nécessaire au runtime. +### 6.2 Compositions -### 6.3 Exemples +Les compositions propres à un exécutable/application utilisent : ```text -config/examples/example.logging.config.json -config/examples/example.composition.config.json -config/examples/example.environment.env +config/composite..json ``` -Aucun secret réel ne figure dans les exemples. - -### 6.4 Compositions runtime - -Une composition concrète appartient au binaire/application qui la consomme et suit : +Exemple futur : ```text -config/.default.config.json +config/composite.ksp-app-wallet-desk.json ``` -Aucune composition runtime concrète n'est créée dans `0.1.3`, car aucun exécutable nécessitant Config n'existe encore dans le workspace. La première composition réelle est prévue avec `ksp-app-config-desk` en `0.1.4`. +Aucun composite runtime fictif n'est créé avant l'existence d'un consumer concret. Le moteur et le schéma génériques peuvent néanmoins être testés dans `0.1.3` par fixtures/examples. -Le contrat générique de composition est néanmoins implémenté et testé dans `0.1.3` via schéma, exemples et fixtures de tests. +### 6.3 Schémas + +Les schémas appartiennent sous : + +```text +config/schemas/ +``` + +Première surface candidate : + +```text +config/schemas/std.logging.schema.json +config/schemas/composite.schema.json +``` + +La nomenclature d'un futur document suit la même famille : + +```text +std.store.json +std.store.schema.json +``` + +### 6.4 Exemples + +Les exemples appartiennent sous : + +```text +config/examples/ +``` + +Exemples candidats : + +```text +config/examples/std.logging.example.json +config/examples/composite.example.json +``` + +Les exemples ne contiennent aucun vrai secret. + +### 6.5 `.env` + +Le fichier d'environnement local par défaut est le fichier conventionnel : + +```text +.env +``` + +à la racine runtime/workspace fournie à Config. + +Il reste ignoré par Git. Un éventuel `.env.example` peut être versionné plus tard lorsqu'une première variable concrète doit être documentée. + +La racine runtime et les chemins Config doivent être fournis explicitement à la session/locator Config ; `ksp-config-lib` ne doit pas rendre son comportement dépendant d'un current working directory implicite. ## 7. Contrat commun des documents JSON -Chaque document Config JSON KSP commence par : +Chaque document JSON KSP possède une version de format : ```json { @@ -275,28 +321,32 @@ Chaque document Config JSON KSP commence par : } ``` -`format_version` est obligatoire et permet à Config de refuser explicitement une génération qu'il ne sait pas lire ou réécrire. +Politique : -Politique retenue : +- `format_version` obligatoire ; +- version inconnue refusée ; +- JSON syntaxiquement invalide refusé ; +- validation par le schéma correspondant avant utilisation runtime ; +- invariants sémantiques supplémentaires après validation schema ; +- document source modifiable représenté par un type sérialisable ; +- configuration effective contenant potentiellement des secrets non sérialisable aveuglément ; +- persistence JSON avec format stable/lisible et newline final ; +- aucun secret ajouté implicitement dans un message d'erreur ou un `Debug`. -- le format initial est `1` ; -- une version inconnue est refusée, jamais réécrite silencieusement ; -- `additionalProperties: false` est utilisé lorsque le contrat est fermé ; -- les documents JSON source peuvent dériver `Serialize`/`Deserialize` parce que la persistence fait partie de leur contrat ; -- une projection runtime résolue susceptible de contenir des secrets ne dérive pas automatiquement `Serialize` ou `Debug` ; -- la sauvegarde JSON produit un format canonique lisible avec newline final ; -- la conservation byte-for-byte des espaces n'est pas un contrat ; la conservation sémantique de la version et des champs l'est. +Les placeholders d'environnement sont autorisés uniquement dans les **valeurs string** du JSON. Ils ne sont pas interprétés dans les noms de propriétés. -## 8. Premier document spécialisé : Logging +Le schéma source doit donc autoriser explicitement une valeur littérale ou une expression Config lorsqu'un champ est substituable. -`logging.config.json` reste le seul document spécialisé créé dans la première surface car Logging est le seul composant runtime déjà développé qui nécessite une configuration. +## 8. Premier document spécialisé : `std.logging.json` -Structure conceptuelle retenue : +Logging est le seul composant runtime existant qui justifie aujourd'hui un document Config réel. + +Structure conceptuelle candidate : ```json { "format_version": 1, - "logs_directory": "logs", + "logs_directory": "${KSP_LOGS_DIRECTORY:-logs}", "default_profile": "default", "profiles": [ { @@ -319,152 +369,97 @@ Structure conceptuelle retenue : Décisions : - `logs_directory` est global, hors profils ; -- `default_profile` est global, autonome, et doit référencer un profil existant ; +- son fallback est exprimé dans le document au point d'usage ; +- `default_profile` est global et référence un profil existant ; - les noms de profils sont uniques ; -- `file` ne duplique pas `logs_directory` ; Config construit le `FileSettings.directory` final à partir de la racine globale ; -- `console: null` ou absence de console signifie sortie console désactivée ; -- `file: null` ou absence de file signifie sortie fichier désactivée ; -- `target_filters` conserve l'ordre du document ; -- les targets restent des prefixes KSP acceptés par `LoggingSettings::validate()` ; -- Config valide sa propre syntaxe/document puis appelle aussi la validation publique Logging après conversion. +- `file` ne duplique pas le répertoire global ; +- console/file peuvent être désactivés selon le schéma final ; +- `target_filters` conserve l'ordre source ; +- Config valide le document puis construit `LoggingSettings` ; +- `LoggingSettings::validate()` reste l'ultime validation du contrat Logging. -## 9. Contrat de composition générique +`std.logging.json` sert de premier test réel du moteur générique, mais son modèle ne doit pas enfermer Config dans Logging. -Le format de composition n'énumère pas tous les futurs domaines dans une structure rigide. Il référence des identifiants de documents enregistrés par Config. +## 9. Paramètres globaux et profils -Structure conceptuelle : - -```json -{ - "format_version": 1, - "owner_namespace": "ksp", - "default_profile": "default", - "documents": { - "logging": "logging.config.json" - }, - "profiles": [ - { - "name": "default", - "document_profiles": {} - }, - { - "name": "diagnostic", - "document_profiles": { - "logging": "diagnostic" - } - } - ] -} -``` - -Décisions : - -- `owner_namespace` est obligatoire et vaut `ksp` ou `kspb` ; il détermine le selector de profil de composition autorisé sans modifier la propriété des documents spécialisés inclus ; -- `default_profile` du composite sélectionne un profil de composition par défaut ; le nom `active_profile` n'est pas conservé dans le fichier source, car « actif » est un état runtime ; -- `documents` associe un identifiant de document KSP connu à un chemin ; -- un chemin relatif est résolu relativement au répertoire contenant la composition puis doit rester sous `ConfigRoot` ; -- les chemins absolus et les traversées hors `ConfigRoot` sont refusés ; -- un document référencé est lu uniquement par Config ; -- `document_profiles` peut remplacer le profil d'un document spécialisé ; -- l'absence d'override utilise le `default_profile` propre au document spécialisé ; -- un override vers un profil inexistant est une erreur avant construction de la configuration effective ; -- une clé d'override absente de `documents` est une erreur ; -- un identifiant de document inconnu de la version courante de Config est refusé au lieu d'être ignoré ; -- la composition n'offre pas de generic JSON patch de champs spécialisés : les valeurs restent possédées par leur document spécialisé. - -Dans `0.1.3`, le seul identifiant de document enregistré est : +Un document spécialisé distingue : ```text -logging +paramètres globaux ++ default_profile ++ profiles[] ``` -## 10. Sélection des profils +Une valeur qui ne varie pas avec le profil reste globale. -Trois niveaux sont distingués : +Le résultat effectif d'un document spécialisé est conceptuellement : -1. profil de composition ; -2. profil d'un document spécialisé ; -3. overrides de valeurs par environnement. +```text +globals ++ selected profile ++ environment substitutions contained in those values +``` -### 10.1 Sans composition +Le profil ne recopie pas artificiellement les globals. -Pour un document spécialisé chargé directement : +Sans composition : ```text profil explicitement demandé par API sinon document.default_profile ``` -### 10.2 Avec composition +Un `default_profile` absent peut être autorisé uniquement pour un type de document dont le contrat le prévoit explicitement. Pour `std.logging.json`, il est requis. -Pour la composition : +## 10. Contrat de composition générique -```text -profil de composition explicitement demandé par API - sinon selector d'environnement possédé par le namespace du composite - sinon composition.default_profile +Une composition assemble plusieurs documents spécialisés sans dupliquer leur contenu. + +Structure conceptuelle : + +```json +{ + "format_version": 1, + "default_profile": "default", + "documents": { + "logging": { + "source": "std.logging.json" + } + }, + "profiles": [ + { + "name": "default", + "documents": { + "logging": { + "profile": "default" + } + } + } + ] +} ``` -Selectors réservés : +Principes : -```text -KSP_CONFIG_PROFILE -> composition KSP -KSPB_CONFIG_PROFILE -> future composition KSPB -``` +- la composition référence des documents spécialisés ; +- chaque document conserve ses globals ; +- une composition peut choisir le profil d'un document ; +- sans choix explicite, le `default_profile` du document est utilisé ; +- le composite ne recopie pas les paramètres spécialisés ; +- un profil composite assemble donc les **paramètres globaux** du document et le **profil sélectionné** de ce document ; +- un document référencé est toujours lu et résolu par Config ; +- profil/document inexistant = erreur ; +- aucun JSON patch générique n'est introduit en `0.1.3` sans besoin concret. -`KSPB_CONFIG_PROFILE` est fixé par le contrat mais n'a aucun consumer réel en `0.1.3`. Config n'applique jamais simultanément les deux selectors : `composition.owner_namespace` choisit lequel est admissible. +Cette structure répond au besoin « un composite pioche dans les documents et leurs profils/paramètres » sans dupliquer les valeurs. -Pour ce selector, la precedence est : +Les références cross-document à une propriété individuelle ne sont pas ouvertes tant qu'un cas concret ne les exige pas. -```text -profil explicite API -> variable du processus -> entrée environment.env -> composition.default_profile -``` +## 11. Modèle d'environnement -Puis, pour chaque document : +### 11.1 Namespaces -```text -composition.profile.document_profiles[document] - sinon document.default_profile -``` - -Le selector d'environnement du profil de composition est un contrôle de sélection, distinct des overrides de valeurs décrits plus bas. - -## 11. Résolution complète et provenance - -L'ordre normatif retenu est : - -```text -1. locator Config / composition -2. lecture + parsing du document source -3. validation schema/source -4. résolution de la composition -5. sélection du profil de composition -6. sélection du profil de chaque document -7. fusion globals + profil spécialisé -8. application des bindings d'environnement explicites -9. validation de la valeur effective -10. conversion vers le contrat runtime propriétaire -``` - -Pour une clé effective, Config doit pouvoir conserver une provenance bornée : - -```text -DocumentGlobal -DocumentProfile { profile } -EnvironmentFile { variable } -ProcessEnvironment { variable } -``` - -Cette provenance sert aux diagnostics et au management, sans inclure la valeur secrète elle-même. - -## 12. Environnement KSP/KSPB - -### 12.1 Namespaces - -Les seuls namespaces applicatifs reconnus sont : +Les variables applicatives admises sont : ```text KSP_SECRET_* @@ -476,328 +471,424 @@ KSPB_PUBLIC_* KSPB_* ``` -Ordre de sensibilité, du plus fort au plus faible : +Classification : + +```text +KSP_SECRET_* / KSPB_SECRET_* -> Secret +KSP_PUBLIC_* / KSPB_PUBLIC_* -> Public +autre KSP_* / KSPB_* -> Internal +``` + +Ordre de sensibilité : ```text Secret > Internal > Public ``` -L'ordre de reconnaissance nominale reste `*_SECRET_*`, puis `*_PUBLIC_*`, puis le namespace général `KSP_*`/`KSPB_*`, afin que le préfixe général ne masque jamais les deux classes explicites. +Un nom hors namespace KSP/KSPB n'est pas une variable applicative gérée par le moteur Config générique, sauf éventuel bootstrap technique explicitement documenté plus tard. -Concrètement : +### 11.2 Sources et priorité -- `KSP_SECRET_*` / `KSPB_SECRET_*` -> `Secret` ; -- `KSP_PUBLIC_*` / `KSPB_PUBLIC_*` -> `Public` ; -- autre `KSP_*` / `KSPB_*` -> `Internal` ; -- un nom hors namespace n'est pas une variable applicative gérée par Config. - -### 12.2 Pas de mapping automatique par transformation de nom - -Config n'infère pas qu'une clé JSON quelconque possède automatiquement un override à partir de son chemin. - -Chaque override est un binding déclaré explicitement par Config : +Pour une variable `NAME`, la résolution est : ```text -document + clé effective + variable + type + sensibilité +1. environnement réel du processus +2. .env +3. fallback déclaré au point d'usage +4. missing ``` -Un binding dont le namespace nominal contredit la sensibilité du champ est refusé dans les tests/audits de la crate. +Donc : -Cette politique évite : - -- les collisions de noms ; -- les overrides accidentels ; -- les conversions de type implicites ; -- la fuite d'un champ secret sous un préfixe public ; -- l'interpolation arbitraire de secrets dans des chaînes opaques. - -### 12.3 Sources d'environnement et precedence - -Config construit une vue d'environnement sans modifier l'environnement du processus : - -```text -valeur du processus - > valeur de config/environment.env - > valeur du document/profil +```bash +export KSP_PUBLIC_FOO=console ``` -Config ne parcourt pas globalement toutes les variables du processus. Il lit uniquement les noms exacts enregistrés dans ses descriptors/bindings ainsi que ses variables bootstrap. Une valeur process non UTF-8 pour un binding attendu est une erreur d'override sans inclure la valeur dans le diagnostic. +est prioritaire sur : -Le fichier par défaut peut être remplacé par le bootstrap interne : - -```text -KSP_ENV_FILE +```dotenv +KSP_PUBLIC_FOO=dotenv ``` -Ordre de sélection du fichier : +et les deux sont prioritaires sur : ```text -chemin explicite fourni à l'API Config -> KSP_ENV_FILE du processus -> config/environment.env +${KSP_PUBLIC_FOO:-fallback} ``` -`KSP_ENV_FILE` est `Internal`, est lu par Config uniquement depuis l'environnement du processus et n'est pas lu depuis le fichier qu'il sert précisément à sélectionner. Sa valeur relative est résolue depuis `ConfigRoot`; une valeur qui sortirait de cette racine est refusée. +### 11.3 Sémantique du fallback -Le fichier géré n'est pas un stockage arbitraire de noms. Une mutation publique de management ne peut créer/modifier/supprimer qu'une variable enregistrée par un descriptor Config et marquée writable. Un nom namespacé mais inconnu dans `environment.env` est refusé comme erreur de document au lieu d'être silencieusement ignoré. - -### 12.4 Variables de contrôle Config - -Les variables de contrôle initiales sont distinctes des bindings de valeurs Logging : - -| Variable | Classe | Source admise | Writable par Management | Rôle | -|-----------------------|----------|------------------------------|-----------------------------------------------|-------------------------------------------------------------------| -| `KSP_ENV_FILE` | Internal | process uniquement | non | sélectionner le fichier d'environnement géré | -| `KSP_CONFIG_PROFILE` | Internal | process ou `environment.env` | oui | sélectionner le profil d'une composition `owner_namespace = ksp` | -| `KSPB_CONFIG_PROFILE` | Internal | process ou `environment.env` | oui, lorsque le support KSPB devient consommé | sélectionner le profil d'une composition `owner_namespace = kspb` | - -Ces noms sont des descriptors Config enregistrés, pas des exceptions lues ad hoc par les applications. - -### 12.5 Rust 2024 et écriture de l'environnement - -En Rust 2024, `std::env::set_var` et `std::env::remove_var` sont `unsafe`. KSP interdit `unsafe`. - -Décision : - -- `ksp-config-lib` peut lire l'environnement du processus ; -- `ksp-config-lib` ne modifie jamais l'environnement global du processus ; -- la surface de management peut modifier atomiquement `config/environment.env` ou un fichier explicitement sélectionné ; -- une variable du processus continue à dominer la valeur persistée et peut donc empêcher une mutation de devenir effective immédiatement ; -- le résultat de mutation doit le signaler explicitement. - -### 12.6 Bindings Logging initiaux - -Première allowlist candidate : - -| Clé effective | Variable | Classe | Type | -|---------------------------------|--------------------------------|----------|----------------------| -| `logging.logs_directory` | `KSP_LOGS_DIRECTORY` | internal | path/string non vide | -| `logging.default_filter` | `KSP_LOGGING_DEFAULT_FILTER` | internal | enum log level | -| `logging.span_events` | `KSP_LOGGING_SPAN_EVENTS` | internal | enum span events | -| `logging.console` | `KSP_LOGGING_CONSOLE` | internal | `off |stdout|stderr` | -| `logging.file.enabled` | `KSP_LOGGING_FILE_ENABLED` | internal | bool | -| `logging.file.file_name_prefix` | `KSP_LOGGING_FILE_NAME_PREFIX` | internal | string non vide | -| `logging.file.rotation` | `KSP_LOGGING_FILE_ROTATION` | internal | `never |hourly|daily` | - -`target_filters` n'a pas d'override d'environnement initial : une liste structurée reste dans le document Logging tant qu'un besoin concret ne justifie pas un encodage dédié. - -Les noms exacts de cette table sont fixés par le plan et pourront uniquement être corrigés avant implémentation par un delta explicite. - -## 13. Sensibilité et surfaces d'accès - -### 13.1 Trois classes +Syntaxes initiales : ```text -Public -Internal -Secret +${KSP_VAR} +${KSP_VAR:-fallback} ``` -Une valeur dérivée de plusieurs inputs prend la sensibilité la plus forte. +Dans KSP, `:-` signifie dans ce contrat : -### 13.2 Runtime +> utiliser le fallback seulement si la variable n'existe ni dans l'environnement du processus ni dans `.env`. -Un consumer runtime obtient uniquement les contrats nécessaires à sa responsabilité. +Une variable explicitement définie avec une chaîne vide est considérée comme **définie**. KSP ne promet donc pas de reproduire toutes les subtilités d'expansion POSIX malgré une syntaxe volontairement familière. -Il ne reçoit pas automatiquement : +Le fallback appartient à l'usage dans le document, pas au `.env`. -- le document source complet ; -- toutes les variables d'environnement ; -- une map générique de secrets ; -- une projection sérialisable de toute la configuration effective. +### 11.4 Interpolation dans une chaîne composée -Pour Logging, le consumer final reçoit un `ksp_logging_lib::LoggingSettings`. +Exemple : -Un futur composant ayant besoin d'un secret recevra une surface typed Config explicitement ajoutée avec ce composant ; `0.1.3` ne crée pas un getter arbitraire `get_secret(name)` pour anticiper des besoins inconnus. - -### 13.3 Diagnostic ordinaire - -Par défaut : - -- `Public` : valeur exposable si la projection demandée la prévoit ; -- `Internal` : utilisable par les contrats runtime typed et par Management, mais sa valeur n'appartient pas à une projection publique générique ; un diagnostic explicitement demandé en mode debug peut l'exposer uniquement lorsque le consumer autorise cette surface ; -- `Secret` : jamais la valeur dans les diagnostics, uniquement état `configured/missing` et provenance non sensible. - -La surface diagnostic sûre est le défaut. Le mode debug ne transforme jamais un `Secret` en valeur diagnostic et n'est pas un substitut à `ConfigManagement`. - -Les erreurs Config ne doivent pas incorporer une valeur secrète rejetée dans leur message ou contexte. - -### 13.4 Management privilégié - -Une application de management doit pouvoir consulter et modifier un secret réel. - -La bibliothèque exposera donc une surface distincte de management, conceptuellement : - -```text -ConfigRuntime -ConfigDiagnostics -ConfigManagement +```json +{ + "url": "https://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY}" +} ``` -`ConfigManagement` peut : - -- lire la valeur source réelle d'un champ secret ; -- lire la valeur réelle d'une entrée d'environnement gérée ; -- modifier/supprimer une valeur autorisée ; -- sauvegarder un document connu ; -- demander une nouvelle résolution effective. - -Cette séparation est une barrière d'API contre les fuites accidentelles, pas un sandbox contre du code Rust hostile dans le même processus. L'authentification et l'autorisation de l'utilisateur final appartiennent à l'application/orchestration. L'application devra fournir explicitement l'autorisation/capacité attendue par la surface management au lieu d'utiliser les APIs runtime ordinaires. - -### 13.5 Frontière Tauri future - -`ksp-config-lib` ne dépend pas de Tauri ni de TS-RS. - -En `0.1.4`, `ksp-app-config-desk` possédera : - -- les commandes Tauri ; -- les DTO publics ; -- les DTO diagnostics ; -- les DTO/commandes privilégiés permettant, après autorisation applicative, d'afficher ou modifier des secrets. - -L'application ne lira jamais directement JSON ou environnement pour implémenter ces commandes. - -## 14. Validation - -La validation est volontairement multi-étapes. - -### 14.1 Document source +Le resolver doit pouvoir produire : ```text -filesystem/path --> UTF-8 +real: +https://mainnet.helius-rpc.com/?api-key=abcdef123456 + +safe: +https://mainnet.helius-rpc.com/?api-key=******** +``` + +Plusieurs placeholders peuvent apparaître dans une même chaîne. + +La sensibilité de la chaîne résolue est la sensibilité la plus forte de tous les placeholders utilisés. + +Si le placeholder est `KSP_SECRET_*`, le fragment substitué est masqué dans la représentation sûre **même lorsque la valeur vient du fallback**. + +### 11.5 `.env` n'est pas le lieu des fallbacks Config + +Le `.env` sert de source locale de valeurs : + +```dotenv +KSP_SECRET_HELIUS_API_KEY=... +KSP_PUBLIC_FOO=bar +``` + +La première version KSP ne dépend pas d'une expansion récursive de variables à l'intérieur du `.env`. Les fallbacks et compositions sont résolus dans les documents Config via `${...}`. + +Le parser `.env` retenu doit au minimum gérer proprement : + +- lignes vides ; +- commentaires ; +- `NAME=VALUE` ; +- valeurs usuelles non quotées ; +- valeurs quotées nécessaires aux espaces/caractères spéciaux ; +- noms KSP/KSPB ; +- erreurs de syntaxe diagnostics sans fuite de secret. + +La grammaire exacte et la stratégie de round-trip sont fixées au delta qui implémente le parser, mais aucun loader ne doit écraser les variables déjà présentes dans le processus. + +## 12. Référence d'environnement = déclaration d'usage + +Le plan ne maintient plus de table statique du type : + +```text +logging.logs_directory -> KSP_LOGS_DIRECTORY +``` + +La déclaration : + +```json +"logs_directory": "${KSP_LOGS_DIRECTORY:-logs}" +``` + +est suffisante pour dire à Config : + +- quelle variable est utilisée ; +- où elle est utilisée ; +- quel fallback est prévu ; +- quelle sensibilité s'applique d'après son nom ; +- quelle provenance doit être reportée après résolution. + +Un document peut donc introduire plus tard : + +```text +${KSP_SECRET_POSTGRES_MAINNET_URL} +${KSP_SECRET_HELIUS_API_KEY} +${KSP_WALLETS_DIRECTORY:-wallets} +``` + +sans ajouter une allowlist centrale spécifique à chaque domaine. + +Config doit néanmoins valider que le nom référencé appartient bien aux namespaces autorisés. + +## 13. API directe de variables d'environnement + +Certains besoins futurs peuvent demander une variable sans qu'elle provienne d'un champ JSON. + +Cette lecture reste possédée par Config et peut être modélisée conceptuellement par une requête : + +```text +name +fallback: Option +``` + +avec exactement la même priorité : + +```text +process > .env > fallback +``` + +Ainsi aucune autre crate n'a de raison d'appeler `std::env::var(...)` pour une variable applicative KSP/KSPB. + +Cette API directe ne devient pas un getter arbitraire permettant d'énumérer tous les secrets. Elle résout un nom explicitement demandé et applique les mêmes règles de sensibilité/diagnostic. + +## 14. Provenance et résultat résolu + +Une valeur effective ne doit pas être réduite trop tôt à un `String` nu lorsque sa provenance ou sa sensibilité sont nécessaires. + +Conceptuellement, Config doit pouvoir représenter : + +```text +ResolvedValue + value valeur réelle destinée au runtime + safe_value représentation sûre destinée aux logs/diagnostics + sensitivity Public | Internal | Secret + provenance source(s) ayant participé à la résolution +``` + +Pour une chaîne composée, la provenance peut contenir plusieurs segments/références. + +Sources candidates : + +```text +DocumentLiteral +EnvironmentProcess { name } +EnvironmentDotEnv { name } +EnvironmentFallback { name } +``` + +Un type contenant une valeur secrète ne doit pas dériver un `Debug` qui révèle `value`. Son `Debug`/`Display` par défaut doit utiliser la représentation sûre ou ne pas être implémenté. + +L'accès à la valeur réelle doit être explicite dans l'API. + +## 15. Secret, public, internal et redaction + +### 15.1 `Public` + +Une valeur dérivée uniquement de `KSP_PUBLIC_*`/`KSPB_PUBLIC_*` peut être exposée dans une projection publique lorsque le contrat applicatif le prévoit. + +### 15.2 `Internal` + +Une valeur `KSP_*`/`KSPB_*` non public/secret est utilisable par le runtime. Son exposition générique externe n'est pas automatique ; elle peut être montrée dans un diagnostic debug explicitement prévu. + +### 15.3 `Secret` + +Une valeur provenant d'un `KSP_SECRET_*`/`KSPB_SECRET_*` : + +- doit être accessible en clair au runtime légitime qui en a besoin ; +- doit être accessible en clair à une surface de management explicitement privilégiée lorsqu'elle doit l'afficher/modifier ; +- ne doit jamais apparaître en clair dans les logs Config ; +- ne doit jamais apparaître en clair dans un message d'erreur ordinaire ; +- ne doit pas être exposée par un `Debug` générique ; +- doit être remplacée par une représentation telle que `********` dans une chaîne destinée au logging/diagnostic. + +Une URL contenant un secret reste donc utilisable réellement par un futur transport tout en offrant une chaîne sûre pour le logging. + +### 15.4 Limite de la garantie + +`ksp-config-lib` fournit les types et représentations empêchant les fuites accidentelles dans le chemin normal. Il ne peut pas empêcher un consumer qui demande explicitement la valeur réelle puis choisit volontairement de la logger. + +Les règles KSP doivent donc imposer aux consumers d'utiliser la représentation sûre dans les logs. + +`ksp-logging-lib` ne scanne toujours pas les messages à la recherche de secrets. + +## 16. Variables manquantes et warning obligatoire + +Cas : + +```json +{ + "url": "${KSP_PUBLIC_RPC_URL}" +} +``` + +Si `KSP_PUBLIC_RPC_URL` : + +- n'existe pas dans le processus ; +- n'existe pas dans `.env` ; +- n'a pas de fallback ; + +alors Config doit au minimum : + +1. produire un diagnostic structuré `missing environment variable without fallback` ; +2. émettre un `warn` sous le target `ksp-config-lib` lorsque Logging est disponible ; +3. inclure le nom de variable, le document et le chemin JSON ; +4. ne jamais inclure une valeur secrète ; +5. considérer la résolution effective comme incomplète. + +Pour une configuration runtime qui exige une valeur effective complète, cette situation devient une erreur de résolution et empêche la construction du contrat runtime. + +La lecture/édition du document source reste toutefois possible dans une application de management afin que l'utilisateur puisse corriger la configuration. + +Exemple de diagnostic sûr : + +```text +target = ksp-config-lib +level = warn +variable = KSP_SECRET_HELIUS_API_KEY +document = config/std.onchain-transport.json +path = $.profiles[0].url +reason = environment variable is missing and no fallback is declared +``` + +Le nom de la variable n'est pas secret ; sa valeur éventuelle l'est. + +## 17. Validation en plusieurs phases + +### 17.1 Document source + +Pipeline : + +```text +path +-> read UTF-8 -> JSON syntax -> format_version --> JSON Schema --> typed deserialize --> invariants sémantiques du document +-> JSON Schema source +-> typed source document +-> invariants sémantiques source ``` -### 14.2 Composition +Le schéma valide le **fichier tel qu'il est écrit**, placeholders compris. -Vérifier notamment : +### 17.2 Sélection profil/composition -- `default_profile` existe ; -- noms de profils uniques ; -- identifiants de documents connus ; -- sources lisibles ; -- override de profil vers un profil existant ; -- aucune clé `document_profiles` sans source correspondante. +Puis : -### 14.3 Environnement +```text +select composition profile if any +-> select each specialized document profile +-> combine document globals + selected profile +``` -Pour chaque binding appliqué : +### 17.3 Résolution environnement -- nom exact ; -- source utilisée ; -- type parsable ; -- enum/bornes valides ; -- sensibilité cohérente ; -- aucune valeur secrète dans le diagnostic d'échec. +Puis, pour chaque chaîne substituable : -### 14.4 Configuration effective +```text +parse placeholders +-> process lookup +-> .env lookup +-> fallback +-> missing diagnostic +-> build real + safe value + provenance + sensitivity +``` -Après overrides : +### 17.4 Validation effective -- invariants Config ; -- invariants propres au document ; -- conversion vers le contrat du composant ; -- validation publique du composant propriétaire lorsque disponible. +Après résolution : + +- aucun placeholder requis ne doit rester non résolu pour un runtime complet ; +- les contraintes métier effectives sont vérifiées ; +- la conversion vers le contrat du composant est exécutée ; +- le composant propriétaire valide son propre contrat public lorsque disponible. Pour Logging : ```text -ResolvedLoggingConfig +std.logging.json +-> schema/source validation +-> selected profile +-> env resolution +-> ResolvedLoggingConfig -> LoggingSettings -> LoggingSettings::validate() ``` -## 15. Erreurs Config +Cette séparation évite de confondre « JSON source valide » et « configuration runtime utilisable ». -Les codes sont possédés par `ksp-config-lib` sous le domaine : +## 18. Lecture et mutation du `.env` + +### 18.1 Lecture + +Config charge le `.env` sans remplacer les valeurs déjà présentes dans l'environnement du processus. + +Il construit sa propre vue : ```text -config +ProcessEnvironment +DotEnv +Fallback ``` -Candidats fixés pour être introduits uniquement lorsqu'ils deviennent nécessaires : +et choisit la source effective selon la priorité définie. + +### 18.2 Mutation persistante + +La surface management de Config doit pouvoir : ```text -config.document_not_found -config.document_read_failed -config.invalid_utf8 -config.invalid_json -config.unsupported_format_version -config.schema_validation_failed -config.invalid_document -config.profile_not_found -config.unknown_document_kind -config.invalid_composition -config.path_outside_root -config.symlink_write_denied -config.invalid_environment_name -config.invalid_environment_file -config.unsupported_environment_format -config.duplicate_environment_variable -config.unknown_environment_variable -config.invalid_environment_override -config.invalid_effective_value -config.management_access_denied -config.persistence_failed +create env entry +update env entry +remove env entry +read env entry ``` -Les erreurs externes utiles sont conservées avec `Error::with_source(...)` lorsque possible. +sur le `.env` sélectionné. -Contexte sûr candidat : +Une modification du `.env` ne prétend pas modifier : + +- le shell parent ; +- une unité systemd ; +- Docker/Kubernetes ; +- l'environnement d'un autre processus. + +Si une variable est aussi définie dans le processus, la modification du `.env` réussit mais la valeur effective reste celle du processus. + +Le résultat de mutation doit donc signaler : ```text -path -document_kind -profile -field -variable -source -operation +source_changed +effective_changed +shadowed_by_process_environment +reload_required ``` -Une valeur secrète n'est jamais ajoutée à `ErrorContext`. +### 18.3 Rust 2024 -## 16. Mutation et persistence +En Rust 2024, la mutation globale du process par `std::env::set_var/remove_var` impose des contraintes `unsafe`; KSP interdit `unsafe`. -### 16.1 Mutation source, pas mutation du snapshot effectif +La première surface KSP traite donc : -Une mutation modifie une source possédée par Config : +- l'environnement du processus comme source **read-only** ; +- `.env` comme source persistante **read/write** possédée par Config. -- document JSON spécialisé ; -- fichier d'environnement géré. +Cette distinction correspond aussi à la réalité opérationnelle : un processus enfant ne peut pas réécrire l'environnement de son shell parent ou d'un service manager déjà lancé. -Elle ne modifie pas directement un objet `LoggingSettings` actif et ne prétend pas que la nouvelle valeur est immédiatement appliquée au runtime. +## 19. Mutation et persistence des documents JSON -### 16.2 Documents modifiables en `0.1.3` +### 19.1 Surface initiale -Surface initiale : +Dans `0.1.3`, le document réellement modifiable est : ```text -logging.config.json -composition fixtures/tests via API générique -config/environment.env +config/std.logging.json ``` -Aucune API d'écriture arbitraire de fichier n'est exposée. +Les fixtures de composition peuvent exercer le moteur générique sans créer un composite runtime fictif. -La composition runtime réelle n'existant pas encore, sa persistence est testée sur fixtures/exemples ; elle sera utilisée concrètement en `0.1.4`. +### 19.2 API -### 16.3 API de mutation +Config ne fournit pas une primitive publique « écrire n'importe quel JSON à n'importe quel chemin ». -Pas de JSON Pointer générique public pour écrire n'importe quel champ. +La mutation porte sur un document Config connu : -Les stratégies retenues sont : +```text +load typed source +-> modify allowed fields +-> validate candidate +-> serialize +-> persist atomically +``` -- remplacement/sauvegarde d'un document source typed après validation complète ; -- helpers typed pour les opérations fréquentes si les tests/applications en démontrent le besoin ; -- `set/remove` explicites uniquement pour un descriptor d'environnement enregistré et marqué writable ; le namespace, le type et la sensibilité sont validés avant persistence. +Une API management peut fournir des helpers plus ergonomiques, mais elle passe toujours par la validation Config. -### 16.4 Atomicité +### 19.3 Atomicité Garantie requise : @@ -808,64 +899,98 @@ nouveau fichier complet jamais un fichier destination partiellement écrit ``` -La persistence doit utiliser un fichier temporaire dans le même répertoire et un remplacement atomique ; aucun fallback `truncate puis écrire` et aucun `delete destination puis rename` n'est accepté. +Même garantie pour `.env`. -Dans la première surface, une destination de mutation qui est elle-même un lien symbolique est refusée avant écriture. Config ne choisit ni de remplacer silencieusement le symlink, ni de suivre implicitement sa cible potentiellement hors `ConfigRoot`. La lecture peut être traitée séparément, mais une source writable doit satisfaire la politique de chemin avant commit. +Un échec de validation ou d'écriture avant commit conserve l'ancien fichier utilisable. -La dépendance candidate `atomic-write-file` est retenue pour cette responsabilité si son audit au moment de l'introduction confirme toujours son adéquation. Elle fournit précisément un commit de remplacement atomique sur Unix, Windows et WASI. +La stratégie exacte d'écriture atomique et la dépendance éventuelle sont auditées au delta qui implémente cette surface. -La sauvegarde suit : +### 19.4 Chemins + +Les documents sous `config/` sont bornés par un `ConfigRoot` explicite. + +Les compositions ne doivent pas pouvoir sortir de cette frontière par un chemin absolu ou `..` non autorisé. + +Le `.env` est une source distincte, localisée par un chemin de session Config explicite avec défaut workspace/runtime `.env`. + +## 20. Surface runtime, diagnostic et management + +Trois intentions doivent être distinguées : ```text -candidate typed --> validation complète --> sérialisation canonique --> écriture temporaire --> flush/fsync selon le backend retenu --> commit atomique --> relecture/résolution de contrôle si nécessaire +ConfigRuntime +ConfigDiagnostics +ConfigManagement ``` -Les détails génériques de durabilité des ACL/xattrs/timestamps ne sont pas promis par `0.1.3` ; la garantie porte d'abord sur l'absence de contenu partiel et la conservation de l'ancien contenu en cas d'échec avant commit. +Les noms Rust exacts pourront évoluer, mais la séparation est normative. -`environment.env` mérite toutefois une politique spécifique parce qu'il peut contenir des secrets : +### 20.1 Runtime -- il reste non versionné ; -- sur Unix, sa création/réécriture doit conserver ou imposer un mode owner-only équivalent à `0600` lorsque l'API plateforme le permet ; -- une permission Unix plus large est un diagnostic de sécurité et doit être corrigée par la surface management avant d'écrire de nouveaux secrets ; -- aucune promesse de chiffrement au repos n'est faite ; -- la stratégie Windows/ACL est auditée au `pre.007` et documentée sans prétendre à une garantie non vérifiée. +Un consumer demande la configuration dont il a besoin. -### 16.5 Desired vs effective +Il peut obtenir une valeur réelle nécessaire au fonctionnement et sa représentation sûre lorsqu'elle peut être loggée. -Une mutation retourne un résultat distinguant au minimum : +Il ne reçoit pas automatiquement une map de tous les secrets ou toute la configuration du projet. + +### 20.2 Diagnostics + +La surface diagnostic ne révèle pas les secrets. + +Elle expose notamment : + +- configured/missing ; +- provenance ; +- source shadowed ; +- safe value ; +- document/path ; +- erreurs de validation. + +### 20.3 Management privilégié + +Une application telle que `ksp-app-config-desk` doit pouvoir, via Config : + +- lire un document source ; +- lire ses valeurs effectives ; +- modifier et sauvegarder le document ; +- inspecter les entrées `.env` ; +- créer/modifier/supprimer une entrée `.env` ; +- révéler explicitement une valeur `Secret` pour affichage/édition légitime ; +- voir qu'une valeur `.env` est shadowed par le process ; +- relancer la résolution après modification. + +Cette surface privilégiée ne rend pas les secrets autorisés dans les logs. L'exception concerne la **visualisation/édition volontaire dans l'UI**, pas le logging. + +L'authentification/autorisation de l'utilisateur final appartient à l'application ; Config fournit une frontière d'API évitant l'exposition accidentelle. + +## 21. Frontière Tauri future + +`ksp-config-lib` ne dépend pas de Tauri ni de TS-RS. + +En `0.1.4`, `ksp-app-config-desk` possédera : + +- commandes Tauri ; +- DTO publics ; +- DTO diagnostics ; +- DTO management privilégiés ; +- logique d'autorisation UI si nécessaire. + +L'application n'utilise ni `std::env`, ni parser dotenv, ni lecture JSON directe pour contourner Config. + +## 22. Relation Config -> Logging + +### 22.1 Conversion ```text -source_changed -effective_changed -shadowed_by_process_environment -reload_required -``` - -Exemple : modifier `KSP_LOGS_DIRECTORY` dans `environment.env` alors qu'une valeur `KSP_LOGS_DIRECTORY` existe dans le processus doit réussir comme persistence source mais signaler que la valeur effective reste shadowed par le processus. - -## 17. Relation Config -> Logging - -### 17.1 Conversion - -`ksp-config-lib` possède le mapping de son document Logging vers les types publics Logging : - -```text -logging.config.json +config/std.logging.json +-> résolution globale/profil/env -> ResolvedLoggingConfig -> ksp_logging_lib::LoggingSettings ``` -Aucune copie structurelle de `LoggingSettings` n'est maintenue comme contrat runtime parallèle. +### 22.2 Lifecycle -### 17.2 Initialisation - -Config n'initialise pas automatiquement Logging au simple chargement d'un document. +Config n'appelle pas automatiquement `initialize` au chargement. L'orchestration fait : @@ -876,148 +1001,137 @@ Config resolve -> conserve LoggingGuard ``` -### 17.3 Hot reload - -Après mutation/relecture : +Puis après modification : ```text Config resolve -> nouveaux LoggingSettings --> comparaison/changement --> orchestration appelle ksp_logging_lib::reinitialize(&mut guard, ...) +-> orchestration décide +-> ksp_logging_lib::reinitialize(&mut guard, ...) ``` -`ksp-config-lib` peut fournir un `ChangeReport` indiquant que Logging est affecté, mais ne possède pas le `LoggingGuard`. +Config peut produire un `ChangeReport`, mais ne possède jamais `LoggingGuard`. -### 17.4 Propriété du guard +### 22.3 Propriété du guard -La règle est rendue concrète par étape : +- dans `0.1.3`, le harness d'intégration possède localement Config + `LoggingGuard` ; +- dans `0.1.4`, l'état backend de `ksp-app-config-desk` les possède ; +- aucun singleton global Config n'est introduit. -- dans `0.1.3`, le harness/test d’intégration qui exercera `initialize` / `reinitialize` possède localement le `LoggingGuard` et sa session Config ; -- dans la première application réelle prévue en `0.1.4`, l’état backend de `ksp-app-config-desk` possédera le `LoggingGuard` et la session Config nécessaires à son orchestration ; -- `ksp-config-lib` ne stocke jamais le `LoggingGuard` et n’introduit aucun singleton global Config ; -- Config peut émettre ses propres événements via `ksp-logging-lib`, sans exiger que Logging ait déjà été initialisé. - -Target racine Config : +Target Config : ```text ksp-config-lib ``` -## 18. Dépendances externes candidates +Les warnings de variables manquantes ou autres diagnostics utiles sont réémis sous ce target. -Aucune dépendance n'est ajoutée dans `pre.001`. +## 23. Erreurs Config candidates -Audit de génération effectué le 2026-08-14 ; les versions exactes seront revérifiées au delta qui les introduit réellement. +Les codes exacts sont ajoutés seulement lorsqu'ils deviennent nécessaires. -### 18.1 `serde` - -Usage réel prévu : - -- `Deserialize` des documents source typed ; -- `Serialize` des documents source modifiables ; -- derives uniquement sur les contrats qui doivent réellement traverser cette frontière. - -Génération candidate observée : +Familles candidates : ```text -^1.0 +config.document_not_found +config.document_read_failed +config.invalid_utf8 +config.invalid_json +config.unsupported_format_version +config.schema_validation_failed +config.invalid_document +config.profile_not_found +config.invalid_composition +config.path_outside_root +config.invalid_environment_name +config.dotenv_read_failed +config.dotenv_parse_failed +config.dotenv_write_failed +config.environment_variable_missing +config.environment_value_invalid +config.placeholder_invalid +config.placeholder_unresolved +config.secret_access_denied +config.mutation_not_allowed +config.persistence_failed +config.effective_validation_failed ``` -### 18.2 `serde_json` +Une erreur liée à `KSP_SECRET_*` peut contenir le **nom** de variable et son origine, mais jamais sa valeur réelle. -Usage : parsing JSON, valeur brute pour validation schema, sérialisation canonique. +## 24. Dépendances externes candidates -Génération candidate : +Aucune dépendance n'est ajoutée dans `pre.001-fix.001`. -```text -^1.0 -``` +Les besoins prévisibles sont : -### 18.3 `jsonschema` +- `serde` : source typed sérialisable/désérialisable ; +- `serde_json` : JSON ; +- moteur JSON Schema ; +- éventuellement une primitive d'écriture atomique ; +- éventuellement une bibliothèque dotenv **uniquement si** elle permet la lecture sans mutation globale du processus et si sa sémantique est compatible avec le contrat KSP. -Usage : validation des schémas JSON source avant conversion effective. +Les versions courantes et les features sont vérifiées uniquement au delta qui introduit réellement la dépendance, puis déclarées sous `[workspace.dependencies]` avec la contrainte de génération retenue par les règles KSP. -Politique candidate : +### 24.1 Parser dotenv -```text -default-features = false -``` +Aucune dépendance dotenv n'est décidée dans le plan. -La première surface n'a besoin ni de résolution HTTP, ni de TLS, ni d'async resolver, car ses schémas sont locaux et auto-contenus. +Le choix doit respecter : -Génération actuelle observée en août 2026 : +- process env non écrasé ; +- accès aux couples clé/valeur pour construire la vue Config ; +- diagnostics contrôlables ; +- possibilité de gérer la persistence `.env` ; +- absence de comportement implicite contraire à la résolution KSP. -```text -^0.49 -``` +Si aucune bibliothèque ne convient proprement, un parser borné peut être possédé par Config. Le but n'est pas d'émuler un shell complet. -### 18.4 Parser `environment.env` possédé par KSP +### 24.2 Placeholder resolver -Aucune dépendance dotenv n'est retenue. +La syntaxe `${NAME}` / `${NAME:-fallback}` dans les documents JSON est une responsabilité KSP, même si un parser dotenv tiers est utilisé pour `.env`. -L'audit de `dotenvy 0.15.7` montre que son iterator ne modifie certes pas l'environnement du processus, mais son parseur effectue des substitutions de variables. Cela contredit le contrat KSP sans interpolation implicite. +Elle ne doit pas être déléguée à une expansion opaque qui ferait perdre provenance, sensibilité et représentation redacted par segment. -La grammaire KSP bornée de `environment.env` est suffisamment petite pour être parsée dans `ksp-config-lib` avec la bibliothèque standard et `serde_json` déjà nécessaire pour l'encodage sûr des valeurs quotées. Ce parser n'essaie pas d'émuler Bash ou un standard dotenv complet. +## 25. Surface Rust conceptuelle -### 18.5 `atomic-write-file` - -Usage : persistence atomique des fichiers Config lorsque la tranche mutation est ouverte. - -Génération candidate observée : - -```text -^0.3 -``` - -### 18.6 Dépendances non retenues initialement - -Ne pas introduire sans besoin : - -```text -tokio -notify -figment -config -clap -ts-rs -tauri -anyhow -thiserror -``` - -Le chargement Config initial est une I/O filesystem locale, bornée et synchrone ; `0.1.3` n'impose donc pas un runtime async à ses consumers. - -## 19. Surface Rust candidate de `ksp-config-lib` - -La structure exacte reste ajustable au développement, mais les responsabilités prévues sont : +Structure interne candidate : ```text src/lib.rs src/error.rs src/document.rs +src/schema.rs +src/profile.rs src/composition.rs src/environment.rs +src/placeholder.rs src/sensitivity.rs +src/resolved.rs src/logging.rs src/diagnostics.rs src/management.rs src/persistence.rs ``` -Les modules restent privés ; l'API nécessaire est réexportée au crate-root. +Les modules restent privés ; l'API utile est réexportée au crate-root. -Types conceptuels à faire émerger uniquement au besoin : +Types conceptuels à faire émerger au besoin : ```text +ConfigRoot +ConfigSession ConfigDocumentKind ConfigSource CompositionDocument CompositionProfile EnvironmentSensitivity EnvironmentSource -EnvironmentBinding +EnvironmentRequest +EnvironmentReference +ResolvedValue ConfigValueOrigin +ConfigDiagnostic ConfigChangeReport ConfigManagementAccess LoggingConfigDocument @@ -1025,179 +1139,225 @@ LoggingProfileConfig ResolvedLoggingConfig ``` -Cette liste n'est pas une obligation de créer tous les types dans `pre.002`. +Cette liste n'impose pas de tout créer dans `pre.002`. -## 20. Audits/tests à introduire +## 26. Audits et tests à introduire -### 20.1 Ownership +### 26.1 Ownership -Tests/audits empêchant : +Empêcher les accès applicatifs directs hors Config : -- `std::env::var`, `var_os`, `vars`, `set_var`, `remove_var` dans les crates KSP hors `ksp-config-lib` pour les variables applicatives KSP/KSPB ; -- lecture/écriture directe de `config/*.config.json` par une autre crate ; +- `std::env::var`, `var_os`, `vars` pour `KSP_*`/`KSPB_*` ; +- loaders dotenv directs ; +- lecture/écriture directe des documents `config/std.*.json` et `config/composite.*.json` ; - dépendance directe `tracing*` depuis Config ; - dépendance inverse Logging -> Config ; -- TS-RS/Tauri dans Config sans décision explicite. +- Tauri/TS-RS dans Config sans décision explicite. -L'audit ne doit pas interdire les usages système légitimes de `std::env` qui ne concernent pas la configuration applicative, par exemple des métadonnées de build/test ; il doit donc être suffisamment ciblé pour éviter un grep faux-positif simpliste. +L'audit doit être ciblé afin de ne pas interdire des usages système de `std::env` sans rapport avec la configuration applicative. -### 20.2 Documents/profils +### 26.2 Documents/schemas Tester : -- `format_version` ; -- default profile présent/absent ; -- noms dupliqués ; -- composition sans override ; -- override valide/invalide ; -- chemins relatifs ; -- rejet chemin absolu/traversée hors `ConfigRoot` ; -- document kind inconnu ; -- invalid JSON/schema/semantic ; -- global hors profil. +- JSON invalide ; +- schema invalide ; +- format version absent/inconnu ; +- globals hors profils ; +- `default_profile` ; +- profils dupliqués ; +- profil absent ; +- composition valide/invalide ; +- chemin hors `ConfigRoot`. -### 20.3 Environnement +### 26.3 Environnement Tester : -- process > environment.env > document ; -- parsing bool/enum/path ; -- binding inconnu non appliqué ; -- namespaces KSP/KSPB ; -- secret/public/internal ; -- aucune valeur secrète dans `Debug`, erreur ou diagnostic générique ; -- `KSP_ENV_FILE` bootstrap ; -- absence de `set_var/remove_var` en production. +```text +process > .env > fallback +``` -Les tests qui nécessitent de contrôler l'environnement du processus doivent éviter les races inter-tests, notamment par processus enfant ou sérialisation explicitement bornée de la fixture de test, sans introduire `unsafe` dans le code KSP. +ainsi que : -### 20.4 Persistence +- variable process seule ; +- variable `.env` seule ; +- process shadowing `.env` ; +- fallback seul ; +- chaîne vide définie ne déclenche pas fallback ; +- variable manquante sans fallback -> diagnostic + warning + résolution runtime incomplète ; +- namespace invalide ; +- plusieurs placeholders dans une chaîne ; +- placeholder malformé ; +- `.env` invalide ; +- commentaires/quotes du `.env` selon grammaire retenue. + +Les tests de process env doivent éviter les races inter-tests, par isolation de processus ou autre stratégie sûre sans `unsafe` KSP. + +### 26.4 Secrets + +Canaries obligatoires : + +```text +SECRET-CANARY +``` + +Tester qu'elles n'apparaissent jamais dans : + +- `Debug` ; +- warning Config ; +- Error/ErrorContext ; +- diagnostics génériques ; +- safe value ; +- logs de tests d'intégration. + +Tester aussi qu'une valeur réelle reste accessible par le contrat runtime/management explicitement autorisé. + +Exemple composé : + +```text +https://provider.invalid/?api-key=${KSP_SECRET_TEST_KEY}&network=${KSP_PUBLIC_NETWORK:-mainnet} +``` + +avec résultat sûr attendu du type : + +```text +https://provider.invalid/?api-key=********&network=mainnet +``` + +### 26.5 Persistence Tester : -- candidate invalide n'altère pas le fichier existant ; -- échec avant commit conserve l'ancien contenu ; -- destination symlink refusée ; -- source writable hors `ConfigRoot` refusée ; -- succès produit un document relisible/validable ; -- newline final ; -- unsupported format refusé ; -- environnement shadowed correctement rapporté. +- candidate JSON invalide n'altère pas le fichier ; +- candidate `.env` invalide n'altère pas le fichier ; +- create/update/remove `.env` ; +- mutation shadowed par process rapportée ; +- succès relisible ; +- failure avant commit conserve ancien contenu ; +- chemins gérés respectés. -### 20.5 Logging adapter +### 26.6 Logging adapter Tester : -- chaque enum Config -> enum Logging ; -- console off/stdout/stderr ; -- file on/off ; -- `logs_directory` global ; +- `logs_directory` global avec fallback ; +- sélection de profil ; +- conversion de chaque enum ; +- console/file ; - target filters ; -- env overrides ; - `LoggingSettings::validate()` ; -- changement Config ne reconfigure rien implicitement ; le guard reste orchestration-owned. +- changement Config sans reconfiguration implicite ; +- `LoggingGuard` reste orchestration-owned. -## 21. Découpage souple des prereleases +## 27. Découpage souple des prereleases -### `0.1.3-pre.001` — audit + brainstorming + plan +### `0.1.3-pre.001` + `pre.001-fix.001` — audit, brainstorming et plan corrigé -- audit stable `0.1.2` ; +- audit `v0.1.2` ; - audit historique ciblé ; -- décisions de ce document ; -- version d'ouverture ; +- choix du propriétaire unique Config ; +- correction vers `.env` conventionnel ; +- interpolation `${...}` + fallback ; +- modèle real/safe/provenance/sensitivity ; - aucune crate/dépendance fonctionnelle Config. -### `0.1.3-pre.002` — crate foundation + erreurs + modèles source +### `0.1.3-pre.002` — fondation de crate + contrats source - créer `ksp-config-lib` ; -- ajouter uniquement les dépendances réellement consommées par cette tranche ; -- contrats communs document/version ; -- document Logging typed ; -- erreurs Config nécessaires ; -- tests unitaires/intégration initiaux. +- dépendances minimales réellement utilisées ; +- erreurs initiales ; +- `ConfigRoot`/session/locator ; +- contrat commun document/version ; +- premiers types `std.logging` source ; +- tests initiaux. -### `0.1.3-pre.003` — JSON Schema + fichiers Config Logging +### `0.1.3-pre.003` — JSON Schema + `std.logging.json` -- créer `config/`, `config/schemas/`, `config/examples/` ; -- schéma Logging ; -- runtime `logging.config.json` minimal sûr ; +- `config/`, `config/schemas/`, `config/examples/` ; +- `std.logging.schema.json` ; +- runtime `config/std.logging.json` ; - exemple Logging ; - pipeline parse/schema/semantic ; -- validation du `default_profile`. +- `default_profile` et globals. -### `0.1.3-pre.004` — composition + résolution profils +### `0.1.3-pre.004` — profils + composition -- contrat generic composition ; -- schéma/exemple ; -- locators et chemins relatifs ; -- profils de composition et overrides spécialisés ; -- provenance document/global/profile. +- résolution de profils spécialisés ; +- contrat composite générique ; +- schema/example composite ; +- sélection de profils documentaires ; +- provenance document/global/profile ; +- aucun composite runtime fictif obligatoire. -### `0.1.3-pre.005` — environnement + sensibilité +### `0.1.3-pre.005` — `.env` + resolver `${...}` +- lecture process env ; +- lecture `.env` sans écrasement process ; +- priorité process > `.env` > fallback ; +- `${NAME}` / `${NAME:-fallback}` ; +- missing diagnostics + warning ; - namespaces KSP/KSPB ; -- `environment.env` + exemple + parser KSP strict sans interpolation ; -- process/env-file precedence ; -- bindings/descriptors explicites Logging ; -- surfaces diagnostic/redaction ; -- audits ownership env. +- tests d'isolation process env. -### `0.1.3-pre.006` — Logging adapter + lifecycle integration +### `0.1.3-pre.006` — sensibilité + valeurs real/safe + Logging adapter -- conversion vers `LoggingSettings` ; -- validations croisées Config/Logging ; -- change report ; -- démonstration initialize/reinitialize en test sans transfert de propriété du `LoggingGuard`. +- `Public/Internal/Secret` ; +- propagation par chaîne composée ; +- redaction par segment ; +- contrat `ResolvedValue` ou équivalent ; +- adaptation `ResolvedLoggingConfig -> LoggingSettings` ; +- tests canary de non-divulgation ; +- démonstration `initialize/reinitialize` avec guard orchestration-owned. -### `0.1.3-pre.007` — management + persistence atomique +### `0.1.3-pre.007` — management + persistence JSON/.env -- surface management explicitement séparée ; -- lecture de secrets autorisée par contrat management ; -- mutation typed Logging ; -- set/remove environment file ; -- atomic write ; -- desired/effective/shadowing report. +- lecture management ; +- reveal secret explicite ; +- mutation typed de `std.logging.json` ; +- create/update/remove `.env` ; +- persistence atomique ; +- desired/effective/shadow report. ### `0.1.3-pre.008` — ownership audits + robustesse -- tests de non-divulgation ; -- tests invalid documents/env ; -- audit des lectures directes Config/env ; +- audits interdisant les accès Config/env directs ailleurs ; +- invalid documents/env/placeholders ; - graphe dépendances/features ; -- corrections de surface publique. +- corrections de surface publique ; +- robustesse des diagnostics sans fuite. ### `0.1.3-pre.009` — clôture - validations finales ; - documentation durable ; -- cleanup/archivage requis uniquement ; -- TODO fermés ou reportés explicitement ; +- cleanup/archivage requis ; +- TODO fermés ou reportés ; - prompt `0.1.4 — ksp-app-config-desk` ; - préparation `rel.001` puis tag stable après validation utilisateur. -Le découpage reste souple : une tranche trop large est scindée ; une tranche devenue inutile est supprimée par correction explicite du plan. +Le découpage reste souple et peut être corrigé par delta explicite. -## 22. Hors scope confirmé +## 28. Hors scope confirmé - application desktop Config dans `0.1.3` ; - Tauri/TS-RS dans `ksp-config-lib` ; -- configuration Transport/Store/Wallet/Execution avant leurs composants ; -- watcher filesystem ; -- reload automatique générique ; -- service de configuration distribué ; +- documents Store/Wallet/Transport/Execution avant leurs composants ; +- watcher filesystem générique ; +- reload automatique de tous les fichiers ; +- service distribué de configuration ; - secrets manager distant ; -- chiffrement maison du fichier d'environnement ; -- modification de l'environnement global du processus ; -- interpolation arbitraire `${...}` dans les chaînes JSON ; -- getter générique de secrets par nom ; +- chiffrement maison de `.env` ; +- modification du shell parent/systemd/Docker par Config ; +- exposition générique de tous les secrets ; +- redaction automatique de messages arbitraires par `ksp-logging-lib` ; - JSON patch arbitraire public ; -- sauvegarde de fichiers hors frontière Config ; - RPC/WS/provider ; - Program/decoder/execution ; - workers/jobs/pipelines ; - trading/ML. -## 23. Validations finales attendues pour `0.1.3` +## 29. Validations finales attendues pour `0.1.3` Au minimum : @@ -1209,38 +1369,38 @@ 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-config-lib -e normal -cargo tree -p ksp-config-lib -e dev ``` -Tout script d'audit réellement présent au moment de la clôture est également exécuté. +Exécuter aussi tout script d'audit réellement présent au moment de la clôture. Une commande non exécutée n'est jamais déclarée réussie. -## 24. Critères de sortie du `pre.001` +## 30. Critères de validation du plan avant `pre.002` -Le plan ferme les questions de cadrage initiales : +Le `pre.001-fix.001` est validable lorsque les décisions suivantes sont acceptées : -- premier document spécialisé : `logging.config.json` uniquement ; -- pas de document applicatif général artificiel ; -- `logs_directory` global hors profils ; -- `default_profile` autonome dans les documents et compositions ; -- composition generic par identifiants de documents + overrides de profils ; -- chemins relatifs de sources résolus depuis le répertoire du composite ; -- environnement par bindings explicites, sans interpolation générique ; -- process env > environment file > document ; -- `composition.owner_namespace` fixe `ksp|kspb` et donc le selector `KSP_CONFIG_PROFILE` ou `KSPB_CONFIG_PROFILE` ; -- `KSP_ENV_FILE` est un bootstrap process-only avec priorité inférieure à un chemin explicite API ; -- `environment.env` utilise la grammaire KSP v1 stricte, sans interpolation, doublons ni noms non enregistrés ; -- `ConfigRoot` borne les sources gérées et les mutations ; -- aucune mutation du process env à cause de Rust 2024 + `unsafe` interdit ; -- management de `environment.env` prévu ; -- classification `Public/Internal/Secret` ; -- lecture de secrets autorisée seulement via surface management/runtime typed explicite ; -- DTO Tauri possédés par l'application future ; -- Config construit `LoggingSettings`, orchestration possède `LoggingGuard` ; -- persistence atomique obligatoire ; -- `0.1.3` reste une seule release bornée ; -- prereleases `pre.002` à `pre.009` dimensionnées. - -Les seules questions laissées volontairement au delta qui introduit une dépendance sont sa version patch exacte et l'audit final de ses features/transitives au jour de l'ajout. +- `ksp-config-lib` est l'unique manager KSP des documents Config et variables applicatives ; +- premier document réel : `config/std.logging.json` ; +- futurs documents : `config/std..json` ; +- futurs composites : `config/composite..json` ; +- JSON validé par schema avant usage ; +- globals hors profils ; +- `default_profile` autonome ; +- composite assemble documents + globals + profils sans recopier les valeurs ; +- `.env` conventionnel à la racine runtime/workspace ; +- environnement du processus > `.env` > fallback ; +- fallback déclaré par `${KSP_VAR:-fallback}` ; +- fallback utilisé seulement lorsque la variable est absente ; une chaîne vide compte comme définie ; +- `${KSP_VAR}` manquant sans fallback produit diagnostic + warning et empêche une résolution runtime complète ; +- une référence `${KSP_...}`/`${KSPB_...}` est elle-même la déclaration d'usage, sans table de bindings centrale ; +- Config peut aussi résoudre explicitement une variable demandée par API ; +- `.env` est read/write via Config ; process env est read-only ; +- les autres crates n'appellent pas `std::env::var(...)` pour les variables applicatives ; +- `Secret` reste disponible au runtime légitime mais dispose toujours d'une représentation sûre/redacted ; +- une chaîne composée conserve valeur réelle + valeur sûre + provenance + sensibilité ; +- `ksp-app-config-desk` pourra révéler/modifier les secrets via une surface management privilégiée ; +- même cette application ne logge jamais les secrets ; +- Config construit `LoggingSettings` et l'orchestration possède `LoggingGuard` ; +- persistence JSON et `.env` atomique ; +- `0.1.3` reste une release unique bornée ; +- aucune implémentation `pre.002` ne commence avant validation utilisateur de ce plan corrigé.