45 KiB
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.
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 :
- les documents de configuration spécialisés ;
- 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.
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.
2. Audit de la base stable 0.1.2
Le workspace stable contient actuellement :
crates/ksp-core-lib
crates/ksp-logging-lib
Le manifest racine utilise :
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.
2.1 Core disponible
ksp-core-lib fournit déjà les contrats nécessaires à Config :
ksp_core_lib::Error
ksp_core_lib::ErrorCode
ksp_core_lib::ErrorContext
ksp_core_lib::Result<T>
Les erreurs propres à Config resteront déclarées dans ksp-config-lib avec le domaine config. Core ne recevra aucune connaissance métier Config.
2.2 Logging disponible
ksp-logging-lib possède déjà :
LoggingSettings
LogFilterLevel
SpanEvents
ConsoleSettings
ConsoleOutput
FileSettings
FileRotation
TargetFilter
LoggingGuard
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.
La direction reste :
ksp-config-lib -> ksp-core-lib
ksp-config-lib -> ksp-logging-lib
ksp-logging-lib -X-> ksp-config-lib
ksp-core-lib -X-> ksp-config-lib
2.3 Règles déjà fixées
Les règles actuelles imposent notamment :
- Rust 2024 ;
unsafe_code = "forbid";- pas de
unwrap,expect,panicou?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 soustests/; - toute dépendance externe centralisée dans
[workspace.dependencies]; - aucune dépendance ajoutée avant un usage réel ;
ksp-logging-libreste l'unique propriétaire direct detracing,tracing-subscriberettracing-appender.
3. Réaudit de la référence historique bot3
L'archive khadhroony-bot3 fournie contient une ancienne ks-config et les documents :
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
Cette base est une référence historique, pas une source de vérité KSP.
3.1 Principes conservés
Les éléments suivants restent pertinents :
- documents spécialisés indépendants ;
- valeurs globales hors profils ;
default_profileautonome 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.
3.2 Éléments explicitement non repris
KSP ne reprend pas aveuglément :
- le document runtime monolithique
AppConfig/ProfileConfighistorique ; - les documents transport/listeners/store/wallet/execution avant l'existence des composants correspondants ;
- une section
applicationopaque 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
.enven 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.
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.
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.
La première surface fonctionnelle contiendra :
- l'infrastructure générique document/profil/composition ;
- le seul document spécialisé actuellement justifié : Logging ;
- l'environnement Config KSP/KSPB avec un fichier d'environnement géré ;
- la classification et les surfaces runtime/diagnostic/management ;
- la mutation/persistence du document Logging et du fichier d'environnement géré ;
- l'adapter
ResolvedLoggingConfig -> ksp_logging_lib::LoggingSettings; - les tests/audits de propriété nécessaires.
Ne sont pas créés dans 0.1.3 : Transport, Wallet, Store, Execution ou une configuration applicative générale fictive.
Cette limitation évite d'insérer une release supplémentaire avant 0.1.4. La séquence reste donc :
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 |
6. Arborescence et nomenclature retenues
6.1 Racine Config et fichiers runtime réels
Les documents runtime réels appartiennent sous une racine Config explicite. Le layout workspace par défaut est :
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
ConfigRootpar..ou équivalent ; - un chemin absolu n'est pas accepté dans un document composite ;
KSP_ENV_FILErelatif est résolu depuisConfigRootet 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 :
config/logging.config.json
config/environment.env
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é :
# ksp-env-format: 1
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; NAMErespecte[A-Z_][A-Z0-9_]*puis doit appartenir àKSP_*ouKSPB_*;- 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_jsonfournit alors l'encodage/décodage de la chaîne ; - aucune expansion
$VAR/${VAR}, aucune substitution shell, aucunexport, 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
config/schemas/logging.config.schema.json
config/schemas/composition.config.schema.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.3 Exemples
config/examples/example.logging.config.json
config/examples/example.composition.config.json
config/examples/example.environment.env
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 :
config/<executable>.default.config.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.
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.
7. Contrat commun des documents JSON
Chaque document Config JSON KSP commence par :
{
"format_version": 1
}
format_version est obligatoire et permet à Config de refuser explicitement une génération qu'il ne sait pas lire ou réécrire.
Politique retenue :
- le format initial est
1; - une version inconnue est refusée, jamais réécrite silencieusement ;
additionalProperties: falseest utilisé lorsque le contrat est fermé ;- les documents JSON source peuvent dériver
Serialize/Deserializeparce que la persistence fait partie de leur contrat ; - une projection runtime résolue susceptible de contenir des secrets ne dérive pas automatiquement
SerializeouDebug; - 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.
8. Premier document spécialisé : Logging
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.
Structure conceptuelle retenue :
{
"format_version": 1,
"logs_directory": "logs",
"default_profile": "default",
"profiles": [
{
"name": "default",
"default_filter": "info",
"span_events": "new_and_close",
"console": {
"output": "stdout"
},
"file": {
"file_name_prefix": "ksp",
"rotation": "daily"
},
"target_filters": []
}
]
}
Décisions :
logs_directoryest global, hors profils ;default_profileest global, autonome, et doit référencer un profil existant ;- les noms de profils sont uniques ;
filene duplique paslogs_directory; Config construit leFileSettings.directoryfinal à partir de la racine globale ;console: nullou absence de console signifie sortie console désactivée ;file: nullou absence de file signifie sortie fichier désactivée ;target_filtersconserve 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.
9. Contrat de composition générique
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.
Structure conceptuelle :
{
"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_namespaceest obligatoire et vautkspoukspb; il détermine le selector de profil de composition autorisé sans modifier la propriété des documents spécialisés inclus ;default_profiledu composite sélectionne un profil de composition par défaut ; le nomactive_profilen'est pas conservé dans le fichier source, car « actif » est un état runtime ;documentsassocie 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
ConfigRootsont refusés ; - un document référencé est lu uniquement par Config ;
document_profilespeut remplacer le profil d'un document spécialisé ;- l'absence d'override utilise le
default_profilepropre 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
documentsest 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 :
logging
10. Sélection des profils
Trois niveaux sont distingués :
- profil de composition ;
- profil d'un document spécialisé ;
- overrides de valeurs par environnement.
10.1 Sans composition
Pour un document spécialisé chargé directement :
profil explicitement demandé par API
sinon document.default_profile
10.2 Avec composition
Pour la composition :
profil de composition explicitement demandé par API
sinon selector d'environnement possédé par le namespace du composite
sinon composition.default_profile
Selectors réservés :
KSP_CONFIG_PROFILE -> composition KSP
KSPB_CONFIG_PROFILE -> future composition KSPB
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.
Pour ce selector, la precedence est :
profil explicite API
> variable du processus
> entrée environment.env
> composition.default_profile
Puis, pour chaque document :
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 :
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 :
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 :
KSP_SECRET_*
KSP_PUBLIC_*
KSP_*
KSPB_SECRET_*
KSPB_PUBLIC_*
KSPB_*
Ordre de sensibilité, du plus fort au plus faible :
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.
Concrètement :
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 :
document + clé effective + variable + type + sensibilité
Un binding dont le namespace nominal contredit la sensibilité du champ est refusé dans les tests/audits de la crate.
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 :
valeur du processus
> valeur de config/environment.env
> valeur du document/profil
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.
Le fichier par défaut peut être remplacé par le bootstrap interne :
KSP_ENV_FILE
Ordre de sélection du fichier :
chemin explicite fourni à l'API Config
> KSP_ENV_FILE du processus
> config/environment.env
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.
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-libpeut lire l'environnement du processus ;ksp-config-libne modifie jamais l'environnement global du processus ;- la surface de management peut modifier atomiquement
config/environment.envou 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 |
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 |
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
Public
Internal
Secret
Une valeur dérivée de plusieurs inputs prend la sensibilité la plus forte.
13.2 Runtime
Un consumer runtime obtient uniquement les contrats nécessaires à sa responsabilité.
Il ne reçoit pas automatiquement :
- 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.
Pour Logging, le consumer final reçoit un ksp_logging_lib::LoggingSettings.
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 étatconfigured/missinget 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 :
ConfigRuntime
ConfigDiagnostics
ConfigManagement
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
filesystem/path
-> UTF-8
-> JSON syntax
-> format_version
-> JSON Schema
-> typed deserialize
-> invariants sémantiques du document
14.2 Composition
Vérifier notamment :
default_profileexiste ;- noms de profils uniques ;
- identifiants de documents connus ;
- sources lisibles ;
- override de profil vers un profil existant ;
- aucune clé
document_profilessans source correspondante.
14.3 Environnement
Pour chaque binding appliqué :
- nom exact ;
- source utilisée ;
- type parsable ;
- enum/bornes valides ;
- sensibilité cohérente ;
- aucune valeur secrète dans le diagnostic d'échec.
14.4 Configuration effective
Après overrides :
- invariants Config ;
- invariants propres au document ;
- conversion vers le contrat du composant ;
- validation publique du composant propriétaire lorsque disponible.
Pour Logging :
ResolvedLoggingConfig
-> LoggingSettings
-> LoggingSettings::validate()
15. Erreurs Config
Les codes sont possédés par ksp-config-lib sous le domaine :
config
Candidats fixés pour être introduits uniquement lorsqu'ils deviennent nécessaires :
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
Les erreurs externes utiles sont conservées avec Error::with_source(...) lorsque possible.
Contexte sûr candidat :
path
document_kind
profile
field
variable
source
operation
Une valeur secrète n'est jamais ajoutée à ErrorContext.
16. Mutation et persistence
16.1 Mutation source, pas mutation du snapshot effectif
Une mutation modifie une source possédée par Config :
- document JSON spécialisé ;
- fichier d'environnement géré.
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.
16.2 Documents modifiables en 0.1.3
Surface initiale :
logging.config.json
composition fixtures/tests via API générique
config/environment.env
Aucune API d'écriture arbitraire de fichier n'est exposée.
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.
16.3 API de mutation
Pas de JSON Pointer générique public pour écrire n'importe quel champ.
Les stratégies retenues sont :
- 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/removeexplicites uniquement pour un descriptor d'environnement enregistré et marqué writable ; le namespace, le type et la sensibilité sont validés avant persistence.
16.4 Atomicité
Garantie requise :
ancien fichier complet
OU
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é.
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.
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 sauvegarde suit :
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
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.
environment.env mérite toutefois une politique spécifique parce qu'il peut contenir des secrets :
- il reste non versionné ;
- sur Unix, sa création/réécriture doit conserver ou imposer un mode owner-only équivalent à
0600lorsque 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.007et documentée sans prétendre à une garantie non vérifiée.
16.5 Desired vs effective
Une mutation retourne un résultat distinguant au minimum :
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 :
logging.config.json
-> ResolvedLoggingConfig
-> ksp_logging_lib::LoggingSettings
Aucune copie structurelle de LoggingSettings n'est maintenue comme contrat runtime parallèle.
17.2 Initialisation
Config n'initialise pas automatiquement Logging au simple chargement d'un document.
L'orchestration fait :
Config resolve
-> LoggingSettings
-> ksp_logging_lib::initialize(...)
-> conserve LoggingGuard
17.3 Hot reload
Après mutation/relecture :
Config resolve
-> nouveaux LoggingSettings
-> comparaison/changement
-> orchestration appelle 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.
17.4 Propriété du guard
La règle est rendue concrète par étape :
- dans
0.1.3, le harness/test d’intégration qui exercerainitialize/reinitializepossède localement leLoggingGuardet sa session Config ; - dans la première application réelle prévue en
0.1.4, l’état backend deksp-app-config-deskpossédera leLoggingGuardet la session Config nécessaires à son orchestration ; ksp-config-libne stocke jamais leLoggingGuardet 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 :
ksp-config-lib
18. Dépendances externes candidates
Aucune dépendance n'est ajoutée dans pre.001.
Audit de génération effectué le 2026-08-14 ; les versions exactes seront revérifiées au delta qui les introduit réellement.
18.1 serde
Usage réel prévu :
Deserializedes documents source typed ;Serializedes documents source modifiables ;- derives uniquement sur les contrats qui doivent réellement traverser cette frontière.
Génération candidate observée :
^1.0
18.2 serde_json
Usage : parsing JSON, valeur brute pour validation schema, sérialisation canonique.
Génération candidate :
^1.0
18.3 jsonschema
Usage : validation des schémas JSON source avant conversion effective.
Politique candidate :
default-features = false
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.
Génération actuelle observée en août 2026 :
^0.49
18.4 Parser environment.env possédé par KSP
Aucune dépendance dotenv n'est retenue.
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.
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.
18.5 atomic-write-file
Usage : persistence atomique des fichiers Config lorsque la tranche mutation est ouverte.
Génération candidate observée :
^0.3
18.6 Dépendances non retenues initialement
Ne pas introduire sans besoin :
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 :
src/lib.rs
src/error.rs
src/document.rs
src/composition.rs
src/environment.rs
src/sensitivity.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.
Types conceptuels à faire émerger uniquement au besoin :
ConfigDocumentKind
ConfigSource
CompositionDocument
CompositionProfile
EnvironmentSensitivity
EnvironmentSource
EnvironmentBinding
ConfigValueOrigin
ConfigChangeReport
ConfigManagementAccess
LoggingConfigDocument
LoggingProfileConfig
ResolvedLoggingConfig
Cette liste n'est pas une obligation de créer tous les types dans pre.002.
20. Audits/tests à introduire
20.1 Ownership
Tests/audits empêchant :
std::env::var,var_os,vars,set_var,remove_vardans les crates KSP horsksp-config-libpour les variables applicatives KSP/KSPB ;- lecture/écriture directe de
config/*.config.jsonpar une autre crate ; - dépendance directe
tracing*depuis Config ; - dépendance inverse Logging -> Config ;
- TS-RS/Tauri 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.
20.2 Documents/profils
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.
20.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_FILEbootstrap ;- absence de
set_var/remove_varen production.
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.
20.4 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
ConfigRootrefusée ; - succès produit un document relisible/validable ;
- newline final ;
- unsupported format refusé ;
- environnement shadowed correctement rapporté.
20.5 Logging adapter
Tester :
- chaque enum Config -> enum Logging ;
- console off/stdout/stderr ;
- file on/off ;
logs_directoryglobal ;- target filters ;
- env overrides ;
LoggingSettings::validate();- changement Config ne reconfigure rien implicitement ; le guard reste orchestration-owned.
21. Découpage souple des prereleases
0.1.3-pre.001 — audit + brainstorming + plan
- audit stable
0.1.2; - audit historique ciblé ;
- décisions de ce document ;
- version d'ouverture ;
- aucune crate/dépendance fonctionnelle Config.
0.1.3-pre.002 — crate foundation + erreurs + modèles 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.
0.1.3-pre.003 — JSON Schema + fichiers Config Logging
- créer
config/,config/schemas/,config/examples/; - schéma Logging ;
- runtime
logging.config.jsonminimal sûr ; - exemple Logging ;
- pipeline parse/schema/semantic ;
- validation du
default_profile.
0.1.3-pre.004 — composition + résolution profils
- contrat generic composition ;
- schéma/exemple ;
- locators et chemins relatifs ;
- profils de composition et overrides spécialisés ;
- provenance document/global/profile.
0.1.3-pre.005 — environnement + sensibilité
- 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.
0.1.3-pre.006 — Logging adapter + lifecycle integration
- conversion vers
LoggingSettings; - validations croisées Config/Logging ;
- change report ;
- démonstration initialize/reinitialize en test sans transfert de propriété du
LoggingGuard.
0.1.3-pre.007 — management + persistence atomique
- 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.
0.1.3-pre.008 — ownership audits + robustesse
- tests de non-divulgation ;
- tests invalid documents/env ;
- audit des lectures directes Config/env ;
- graphe dépendances/features ;
- corrections de surface publique.
0.1.3-pre.009 — clôture
- validations finales ;
- documentation durable ;
- cleanup/archivage requis uniquement ;
- TODO fermés ou reportés explicitement ;
- prompt
0.1.4 — ksp-app-config-desk; - préparation
rel.001puis 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.
22. 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é ;
- 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 ;
- 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
Au minimum :
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test --workspace
cargo tree -p ksp-config-lib
cargo tree -p ksp-config-lib -d
cargo tree -p ksp-config-lib -e features
cargo tree -p ksp-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é.
Une commande non exécutée n'est jamais déclarée réussie.
24. Critères de sortie du pre.001
Le plan ferme les questions de cadrage initiales :
- premier document spécialisé :
logging.config.jsonuniquement ; - pas de document applicatif général artificiel ;
logs_directoryglobal hors profils ;default_profileautonome 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_namespacefixeksp|kspbet donc le selectorKSP_CONFIG_PROFILEouKSPB_CONFIG_PROFILE;KSP_ENV_FILEest un bootstrap process-only avec priorité inférieure à un chemin explicite API ;environment.envutilise la grammaire KSP v1 stricte, sans interpolation, doublons ni noms non enregistrés ;ConfigRootborne les sources gérées et les mutations ;- aucune mutation du process env à cause de Rust 2024 +
unsafeinterdit ; - management de
environment.envpré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èdeLoggingGuard; - persistence atomique obligatoire ;
0.1.3reste une seule release bornée ;- prereleases
pre.002àpre.009dimensionné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.