# Plan `0.1.4` — `ksp-app-config-desk` ## 1. Statut, base et objectif Ce plan ouvre `0.1.4` avec `0.1.4-pre.001`. Cette première tranche reste volontairement une tranche de **brainstorming, audit et planification** : elle ne crée pas encore la crate Tauri, n'ajoute aucune dépendance desktop et ne commence pas l'éditeur fonctionnel. Base fournie et auditée : ```text khadhroony-solana-project-v0.1.3.zip workspace.package.version = "0.1.3" deltas/0.1.3/rel.001.md présent ``` L'archive ne contient pas de métadonnées `.git`. Le tag Git `v0.1.3` ne peut donc pas être revérifié matériellement depuis cette archive seule ; la livraison stable fournie est prise comme base de session, conformément au prérequis utilisateur de publication/tag validés. La mission de `0.1.4` est d'introduire la première application desktop spécialisée KSP : ```text ksp-app-config-desk ``` Elle doit valider réellement la surface stable de `ksp-config-lib` et le lifecycle de `ksp-logging-lib`, tout en restant une couche de composition/interface : ```text ksp-app-config-desk -> ksp-config-lib -> ksp-logging-lib -> ksp-core-lib via les contrats KSP nécessaires ``` L'application ne devient propriétaire ni du parsing Config, ni des schemas, ni des placeholders, ni de `.env`, ni de la classification des secrets, ni de la persistence Config, ni du runtime `tracing`. ## 2. Audit exact de la base stable `0.1.3` ### 2.1 Workspace Le workspace stable contient exactement les crates fonctionnelles suivantes : ```text crates/ksp-core-lib crates/ksp-logging-lib crates/ksp-config-lib ``` Les ressources requises par le prompt sont présentes : ```text config/std.logging.json config/schemas/std.logging.schema.json config/schemas/composite.schema.json config/examples/std.logging.example.json config/examples/composite.example.json .env.example ``` Le `Cargo.toml` racine déclare Rust 2024 et les lints KSP attendus. Les dépendances externes communes sont centralisées sous `[workspace.dependencies]`. ### 2.2 Surface Config réutilisable L'audit confirme notamment : - `ConfigBootstrapOptions` pour `--cfgpath` / `--schemapath` ; - `ConfigFileRegistry`, `ConfigFileId`, `ConfigFileDescriptor` et `--filemap` ; - `ConfigDocumentEngine` ; - validation JSON, JSON Schema et sémantique ; - globals, profils, `default_profile` et provenance ; - composites génériques par `file_id` ; - `ConfigEnvironment` avec priorité process > `.env` > fallback ; - placeholders `${NAME}` et `${NAME:-fallback}` ; - sensibilité `Public` / `Internal` / `Secret` ; - représentations réelle/sûre et provenance ; - `ResolvedLoggingConfig::into_settings()` ; - `ConfigManagement` ; - `ConfigManagement::read_source()` pour lire le source d'un document Config enregistré même lorsqu'il est invalide ; - `ConfigManagement::load_logging_document()` / `save_logging_document()` ; - `environment_report()` ; - `reveal_effective_environment_value()` / `reveal_dotenv_value()` ; - `set_dotenv_value()` / `remove_dotenv_value()`. ### 2.3 Lifecycle Logging déjà compatible avec le hot reload `ksp-logging-lib` possède déjà le contrat essentiel de `0.1.4` : ```text initialize(&LoggingSettings) -> LoggingGuard reinitialize(&mut LoggingGuard, &LoggingSettings) -> Result<()> ``` Le nouveau runtime est préparé avant le swap. Une erreur de validation/préparation ou de reload laisse donc le runtime valide précédent actif. `0.1.4` doit **exploiter et démontrer** cette propriété, pas la réimplémenter. ### 2.4 Deux lacunes publiques de Config révélées par l'usage desktop L'audit fait apparaître deux besoins réels qui n'étaient pas nécessaires pour `0.1.3`, mais deviennent bloquants pour un manager extensible. #### A. Inventaire du registre `ConfigFileRegistry` sait : ```text descriptor(file_id) resolve_path(...) ``` mais n'expose pas aujourd'hui de vue publique permettant d'énumérer les descripteurs enregistrés. Construire dans l'application une liste codée en dur de `FILE_ID_*` dupliquerait le registre et empêcherait l'extensibilité demandée. Une petite extension publique de `ksp-config-lib` devra donc fournir une vue en lecture seule/itérable des descripteurs, dans l'ordre déterministe du registre. #### B. Réparation d'un document invalide `ConfigManagement::read_source()` permet volontairement de lire un source invalide. En revanche : ```text load_logging_document() -> nécessite déjà un document valide save_logging_document(&LoggingConfigDocument) -> sauve un candidat typé déjà reconstructible ``` Il n'existe pas encore de frontière publique permettant à une application de soumettre le texte corrigé d'un document enregistré qui était invalide, sans écrire directement le fichier physique. La solution prévue est une API Config bornée, de forme conceptuelle : ```text save_source_candidate(file_id, source_text) ``` Le nom public final sera fixé dans la tranche d'implémentation, mais le contrat est décidé dès maintenant : 1. `file_id` doit être connu et de kind `Config` ; 2. le texte candidat est parsé par Config ; 3. le document est validé contre le schema enregistré ; 4. les invariants sémantiques Config sont exécutés ; 5. rien n'est écrit si une étape échoue ; 6. si tout est valide, Config sérialise/persiste atomiquement le document normalisé ; 7. l'application ne reçoit aucun droit d'écrire un chemin arbitraire. Cette API n'est **pas** un contournement permettant de persister un JSON invalide. Elle constitue précisément la frontière de réparation validée manquante. Ces deux extensions appartiennent à `ksp-config-lib`, avec tests publics/unitaires appropriés ; elles ne doivent pas être simulées dans l'application Tauri. ## 3. Audit des règles Tauri et du gabarit bot3 Référence auditée : ```text khadhroony-bot3_v0.5.3-pre.005-fix010.zip kb-app-demo-desktop ``` La référence est réutilisée par **principes**, pas copiée mécaniquement. ### 3.1 Éléments retenus - package Rust mixte `lib` + `bin` ; - binaire très mince ; - verrou single-instance avant l'entrée Tauri ; - `tauri.rs` centralisant `run` et les wrappers `#[tauri::command]` ; - logique métier/fenêtre hors des wrappers ; - fenêtre `splash` distincte de la fenêtre `main` ; - frontend Vanilla TypeScript + Vite ; - SCSS/SASS et Bootstrap ; - gabarit visuel initial de bot3 comme base à simplifier/affiner, sans recopier les écrans métier ; - même icône de base bot3 (`favicon.png` / `favicon.ico`) tant qu'aucune identité KSP plus spécifique n'est décidée ; - Font Awesome pour l'iconographie ; - organisation Vite explicite avec frontend sous `frontend/` ; - génération TS-RS à la frontière applicative ; - `LoggingGuard` gardé durablement dans l'état backend. ### 3.2 Éléments à refondre ou ne pas reprendre Le modèle bot3 contient encore : ```text SPLASH_MINIMUM_MS = 12100 SPLASH_FADE_MS = 12000 SPLASH_CLOSE_WAIT_MS = 12100 ``` Ces timings codés en dur ne sont pas retenus. KSP introduira un réglage Config/.env résolu via `ksp-config-lib` au moment où le splash runtime sera implémenté. Le frontend bot3 déclare aussi `@fltsci/tauri-plugin-tracing` sans l'importer. KSP ne reprend pas une dépendance frontend inutilisée par simple symétrie. Les dépendances propres aux nombreuses démos bot3 ne sont pas retenues pour Config Desk : - DataTables ; - ECharts ; - `@andypf/json-viewer` ; - SimpleBar ; - resize-observer polyfill ; - `markdown-it` en l'absence de vue de présentation. `init_rustls` n'est pas copié par réflexe. Aucun besoin TLS direct de Config Desk n'est identifié. Le helper ne sera introduit que si une dépendance réellement utilisée l'exige. Le helper bot3 d'ouverture/focus de fenêtre est réduit à une primitive commune adaptée au shell (`show/focus` de `main` après splash) ; aucun helper multi-fenêtres générique n'est ajouté sans deuxième usage. ### 3.3 Décision frontend Le frontend de référence pour `0.1.4` sera : ```text Vanilla TypeScript Vite SCSS via sass-embedded Bootstrap Font Awesome Free ``` Aucun framework React/Vue/Svelte n'est nécessaire pour ce manager spécialisé. Cette décision réduit la surface et reste cohérente avec le modèle bot3 ainsi qu'avec le template Vanilla TypeScript officiellement supporté par Tauri 2. Le premier éditeur raw utilisera un contrôle texte natif correctement stylé ; aucun éditeur de code lourd n'est ajouté tant qu'un besoin fonctionnel ne l'impose pas. ## 4. Audit des dépendances actuelles au 2026-08-16 Aucune dépendance n'est ajoutée par `pre.001`. Les versions suivantes ont été revérifiées depuis les registres/documentations officiels afin de fixer la génération candidate à réévaluer **au moment exact de l'ajout** : | Dépendance | Version actuelle auditée | Usage envisagé | |---------------------------------|-------------------------:|------------------------------------------| | `tauri` | `2.11.5` | runtime desktop | | `tauri-build` | `2.6.3` | build Tauri | | `tauri-plugin-tracing` | `0.3.4` | intégration tracing à la frontière Tauri | | `ts-rs` | `12.0.1` | bindings DTO applicatifs | | `fs2` | `0.4.3` | verrou single-instance | | `@tauri-apps/api` | `2.11.1` | frontend Tauri | | `@tauri-apps/cli` | `2.11.4` | dev/build desktop | | `vite` | `8.2.1` | build frontend | | `typescript` | `7.0.2` | frontend TypeScript | | `sass-embedded` | `1.102.0` | compilation SCSS | | `bootstrap` | `5.3.8` | composants/layout | | `@fortawesome/fontawesome-free` | `7.3.1` | iconographie | Sources d'audit : - - - - - - - - - - - - - - - - Vite 8 reste compatible avec la direction choisie, mais demande une version Node moderne. Le poste de build devra donc être vérifié contre le prérequis Vite au moment de la création du frontend. ### 4.1 Décision explicite `tauri-plugin-tracing` La version auditée `0.3.4` convient à l'ownership KSP sur un point essentiel : **elle n'installe pas de subscriber global par défaut**. Config Desk devra enregistrer le plugin avec un builder qui n'appelle jamais : ```text with_default_subscriber() ``` Le subscriber global reste exclusivement installé par `ksp-logging-lib::initialize()`. Un autre point a été vérifié dans le source `0.3.4` : la commande JS -> Rust `log` émet actuellement des événements `tracing` avec : ```text target: "" ``` Or `ksp-logging-lib` impose aux target filters configurables un prefix `ksp-` et son takeover runtime est centré sur `ksp-`. Décision `0.1.4` : - intégrer le **plugin Rust** à la frontière Tauri sans subscriber propre ; - ne pas utiliser `with_default_subscriber()` ; - ne pas installer une seconde pile `tracing-subscriber` dans l'application ; - ne pas détendre la politique `ksp-*` de `ksp-logging-lib` uniquement pour faire passer le target vide du plugin ; - ne pas ajouter le package JS `@fltsci/tauri-plugin-tracing` tant qu'un adapter réellement fonctionnel et conforme aux targets KSP n'est pas défini ; - pour les événements de test Logging de `0.1.4`, utiliser la façade/macros de `ksp-logging-lib` avec un target KSP contrôlé ; - enregistrer cette incompatibilité comme point à revérifier si une nouvelle version du plugin permet un target frontend namespacé ou si KSP introduit plus tard une extension explicitement conçue de Logging. `tauri-plugin-log` est **explicitement exclu**. ## 5. Layout interne cible de `crates/ksp-app-config-desk` La crate sera ajoutée directement sous : ```text crates/ksp-app-config-desk ``` Layout cible : ```text crates/ksp-app-config-desk/ ├── Cargo.toml ├── README.md ├── USAGE.md ├── build.rs ├── package.json ├── tsconfig.json ├── vite.config.ts ├── tauri.conf.json ├── capabilities/ ├── icons/ ├── frontend/ │ ├── main.html │ ├── splash.html │ ├── ts/ │ │ ├── main.ts │ │ ├── splash.ts │ │ ├── invoke.ts │ │ ├── state.ts │ │ └── bindings/ # généré, ignoré │ └── scss/ │ ├── main.scss │ ├── splash.scss │ └── _shared.scss ├── src/ │ ├── main.rs │ ├── lib.rs │ ├── tauri.rs │ ├── app_state.rs │ ├── bootstrap.rs │ ├── errors.rs │ ├── config_service.rs │ ├── environment_service.rs │ ├── logging_service.rs │ ├── secret_service.rs │ ├── splash.rs │ ├── tw_main.rs │ ├── tw_splash.rs │ ├── dto_common.rs │ ├── dto_documents.rs │ ├── dto_environment.rs │ ├── dto_logging.rs │ └── dto_secret.rs ├── unit_tests/ │ └── ... miroir des modules Rust testés └── tests/ └── ... API publique / intégration bornée ``` Le layout pourra être ajusté lors de la création réelle si Tauri 2 impose un fichier généré spécifique, mais les responsabilités ci-dessous sont fixées. ### 5.1 Contrat `lib` + `bin` Le package est mixte : ```text package : ksp-app-config-desk lib : ksp_app_config_desk_lib bin : ksp-app-config-desk ``` `main.rs` reste minimal : 1. construire/acquérir le verrou single-instance ; 2. collecter les arguments de processus nécessaires au bootstrap ; 3. appeler l'entrée `run(...)` de la bibliothèque ; 4. convertir explicitement le résultat en `ExitCode`. `main.rs` ne lit pas `KSP_*` / `KSPB_*` et ne parse pas lui-même Config. `lib.rs` est limité aux déclarations de modules et réexports réellement nécessaires. `tauri.rs` possède : - `run` ; - le `tauri::Builder` ; - l'enregistrement du plugin tracing ; - l'enregistrement du state ; - **toutes** les annotations `#[tauri::command]` ; - les wrappers très minces qui délèguent aux services/modules ; - les helpers Tauri réellement transverses de démarrage/fenêtres. Aucune annotation `#[tauri::command]` n'est dispersée dans `config_service.rs`, `logging_service.rs`, `tw_*`, etc. ### 5.2 Convention `tw_*` `tw_*` est retenu pour les modules liés à une fenêtre Tauri : ```text tw_main.rs tw_splash.rs ``` Les opérations métier ne sont pas placées dans ces modules. Le shell fonctionnel reste essentiellement monofenêtre ; `tw_main` orchestre la fenêtre, pas la logique Config. ## 6. Modèle d'état applicatif et ownership de `LoggingGuard` L'état backend cible est conceptuellement : ```text AppState ├── ConfigManagement └── Mutex ├── LoggingGuard ├── active_profile_id └── generation/revision runtime ``` Principes : - `ConfigManagement` reste la façade de management ; - son `ConfigDocumentEngine` porte bootstrap + registry ; - `ConfigEnvironment::load()` produit un snapshot frais lorsqu'une résolution runtime doit refléter le process/`.env` courant ; - `LoggingGuard` vit aussi longtemps que l'application ; - guard + métadonnées du profil actif sont protégés ensemble pour éviter un état incohérent après reload ; - l'identifiant de profil actif n'est modifié qu'après succès de `reinitialize()` ; - un échec conserve guard, profil actif et génération précédents. ### 6.1 Bootstrap Logging initial Ordre cible : ```text argv -> ConfigBootstrapOptions / ConfigFileRegistry via ksp-config-lib -> ConfigDocumentEngine -> ConfigEnvironment::load() -> load_resolved_logging_config(None, env) -> ResolvedLoggingConfig::into_settings() -> ksp_logging_lib::initialize(...) -> LoggingGuard -> AppState -> tauri::Builder ``` `None` utilise le `default_profile` du document Logging. Une sélection explicite ultérieure est faite depuis l'UI. Si le document Logging est invalide au démarrage, l'application doit quand même pouvoir devenir un outil de réparation. Il faudra donc prévoir un **fallback de bootstrap applicatif sûr** qui ne duplique pas la configuration Logging : par exemple démarrer avec un settings KSP minimal construit par l'application uniquement pour rendre le manager utilisable, tout en affichant clairement le diagnostic Config. Le contrat exact de ce fallback sera implémenté/testé dans la tranche bootstrap ; il ne doit jamais remplacer silencieusement la configuration utilisateur ni être persisté automatiquement. Ce fallback est un point de vigilance : sans lui, l'exigence « afficher le source brut invalide afin de permettre sa réparation » serait impossible lorsque `std.logging.json` lui-même empêche le démarrage. ## 7. Shell et écrans/panneaux minimums Décision : **une fenêtre principale de management**, plus le splash de démarrage. Les fonctions sont des panneaux/routes internes, pas une collection de fenêtres séparées. Navigation minimum : ```text Vue d'ensemble Documents Profils Environnement Logging ``` ### 7.1 Vue d'ensemble Affiche uniquement des informations sûres : - racines bootstrap Config ; - nombre de documents Config enregistrés ; - état valide/invalide des documents inspectés ; - profil Logging runtime actif ; - génération/revision de reload ; - présence de shadowing environnement ; - dernier résultat de probe Logging. ### 7.2 Documents Fonctions : - lister les documents de kind `Config` issus du registre Config ; - afficher `file_id`, filename mappé, schema associé et path résolu ; - charger/valider un document via Config ; - classifier l'erreur ; - en cas d'invalidité, afficher le source brut fourni par `ConfigManagement::read_source()` ; - permettre l'édition du texte puis soumettre le candidat à l'API Config de réparation validée ; - recharger le document après succès. L'UI n'utilise ni `JSON.parse` comme validateur de vérité, ni un schema frontend dupliqué pour décider si la sauvegarde est valide. Un parsing frontend éventuel ne sert qu'à l'ergonomie ; l'autorité est le résultat backend Config. ### 7.3 Profils Le premier document spécialisé est Logging. L'UI doit montrer : - `default_profile` ; - profils disponibles ; - profil explicitement sélectionné pour inspection ; - source de sélection (`default_profile` ou explicite) ; - globals ; - contenu du profil ; - effective après résolution environnement ; - provenance utile sans valeur Secret réelle. L'inspection générique par `file_id` reste prévue dans le shell, mais `0.1.4` ne crée pas d'éditeur générique de tout schema inconnu. ### 7.4 Environnement Table sûre pour les variables présentes dans les rapports Config : - nom ; - namespace KSP/KSPB ; - sensibilité ; - `safe_value` desired `.env` ; - `safe_value` effective ; - source effective process/`.env` ; - indicateur shadowed ; - actions créer/modifier/supprimer `.env` ; - action privilégiée « Révéler » séparée. Après une mutation `.env`, l'UI affiche explicitement : ```text source modifiée ? valeur effective modifiée ? shadowed par process ? ``` Elle ne prétend jamais modifier l'environnement du parent/process déjà hérité. ### 7.5 Logging Éditeur spécialisé et typé couvrant au minimum : - `default_profile` ; - création d'un profil ; - duplication d'un profil ; - renommage ; - suppression avec garde sur `default_profile` ; - filtre par défaut ; - span events ; - console enabled/output/ANSI/format/filter ; - plusieurs fichiers ; - `output_id` ; - path ; - rotation ; - format ; - filtres level/targets/domains ; - target filters ; - sauvegarde ; - sélection d'un profil à appliquer ; - hot reload ; - émission d'un probe contrôlé. Les opérations frontend produisent des DTO applicatifs ; le service Rust reconstruit/utilise les types publics `LoggingConfigDocument` et sous-contrats de `ksp-config-lib`. Le frontend ne fabrique pas directement le JSON persistant comme source d'autorité. ## 8. Matrice commandes Tauri / services / APIs KSP Les noms ci-dessous sont les noms fonctionnels cibles ; ils pourront être normalisés avant implémentation, mais leurs responsabilités sont fixées. | Commande Tauri | Service interne | API KSP principale | Secret réel ? | |--------------------------------|--------------------------------------|-----------------------------------------------------------------------------|---------------------------------------------:| | `get_app_snapshot` | `config_service` + `logging_service` | registry/management + runtime state | non | | `list_config_documents` | `config_service` | future vue publique du `ConfigFileRegistry` | non | | `inspect_config_document` | `config_service` | `load_validated_document` + `read_source` si erreur | non | | `save_config_source_candidate` | `config_service` | future API Config de réparation validée | non | | `inspect_profile` | `config_service` | `load_resolved_profile` + résolution détaillée | non | | `get_environment_report` | `environment_service` | `ConfigManagement::environment_report` | non | | `set_dotenv_value` | `environment_service` | `ConfigManagement::set_dotenv_value` | entrée potentiellement Secret, jamais loggée | | `remove_dotenv_value` | `environment_service` | `ConfigManagement::remove_dotenv_value` | non | | `reveal_environment_value` | `secret_service` | `reveal_effective_environment_value` ou `reveal_dotenv_value` | **oui** | | `get_logging_editor` | `logging_service` | `load_logging_document` | non | | `save_logging_document` | `logging_service` | `save_logging_document` | non par design Logging | | `apply_logging_profile` | `logging_service` | `ConfigEnvironment::load` + `load_resolved_logging_config` + `reinitialize` | valeurs resolved possibles, jamais DTO/log | | `run_logging_probe` | `logging_service` | macros/façade `ksp-logging-lib` | non, payload fixé | | `splash_frontend_ready` | `splash` | lifecycle Tauri + settings splash déjà résolus | non | Tous les wrappers dans `tauri.rs` : - retournent explicitement `Ok`/`Err` ; - n'utilisent ni `?`, ni `unwrap`, ni `expect`, ni `panic` ; - ne contiennent pas la logique métier ; - convertissent les erreurs vers un DTO sûr sans sérialiser aveuglément `Error::context()`. ## 9. Matrice DTO ordinaires / DTO secrets ### 9.1 DTO ordinaires Familles prévues : ```text AppSnapshotDto ConfigDocumentDescriptorDto ConfigDocumentInspectionDto ConfigDiagnosticDto ProfileInspectionDto EnvironmentVariableReportDto EnvironmentMutationResultDto LoggingDocumentDto LoggingProfileDto LoggingConsoleDto LoggingFileDto LoggingFilterDto LoggingRuntimeDto LoggingProbeResultDto ``` Règles : - valeurs environnement = safe/redacted uniquement ; - aucun champ « real_value » générique ; - aucune copie brute d'un contexte d'erreur pouvant contenir une donnée sensible ; - `ConfigDiagnosticDto` contient au minimum domaine/code/message/catégorie + métadonnées sûres connues de la requête (`file_id`, éventuellement path Config), jamais une source externe arbitraire ; - bindings TS-RS dans la crate applicative. ### 9.2 Classification des diagnostics L'application classe par **ErrorCode stable**, pas par parsing du texte : ```text Json Schema Semantic Effective Environment BootstrapOrMapping PersistenceOrManagement RuntimeLogging Tauri ``` Exemples : - `json_syntax_invalid` -> `Json` ; - `schema_invalid` / `schema_validation_failed` -> `Schema` ; - `document_semantic_invalid` -> `Semantic` ; - `effective_config_invalid` -> `Effective` ; - erreurs de placeholder/variable -> `Environment`. ### 9.3 DTO secret privilégié Le reveal utilise une commande et des DTO **séparés** : ```text SecretRevealRequestDto SecretRevealResponseDto ``` Le response DTO : - est sérialisable vers Tauri ; - n'est pas incorporé dans un snapshot global ; - n'est pas mis en cache dans `AppState` ; - n'est pas cloné/Debug par convenance ; - n'est jamais inclus dans un diagnostic/log. Le frontend : - n'appelle reveal qu'après action explicite sur une variable nommée ; - affiche un modal de confirmation mentionnant la variable et la source demandée ; - affiche le secret dans un contrôle transitoire masqué par défaut ; - retire la valeur du state frontend à la fermeture/changement de panneau ; - n'utilise ni localStorage, ni sessionStorage, ni persistance automatique pour cette valeur. ## 10. Modèle d'autorisation pour les secrets en `0.1.4` Le threat model de la première version est la **prévention de divulgation accidentelle** dans les DTO généraux, logs, diagnostics, snapshots et état UI persistant. L'application est locale et hérite de l'authentification de la session desktop qui l'exécute. `0.1.4` n'introduit pas de mot de passe KSP maison, de biométrie, de keychain ni de secrets manager distant. L'autorisation applicative retenue est donc : 1. le reveal n'existe que dans une commande Tauri distincte ; 2. la requête porte exactement le nom de variable et la source (`effective` ou `.env`) ; 3. le frontend impose une confirmation utilisateur explicite juste avant l'appel ; 4. le backend revérifie que le nom appartient bien aux namespaces KSP/KSPB et applique sa policy de reveal ; 5. seule la méthode `reveal_*` Config est appelée ; 6. la réponse n'est jamais conservée dans l'état backend ; 7. aucun log/probe ne reçoit la valeur. Cette barrière n'est pas présentée comme une ré-authentification forte contre une webview déjà compromise. Une auth OS forte éventuelle est hors scope de `0.1.4` et devra être conçue séparément si le threat model futur l'exige. ## 11. Hot reload Logging : flux et preuve observable ### 11.1 Sauvegarde et application restent deux opérations Flux : ```text éditer -> sauver document via Config -> choisir profil à appliquer -> construire ConfigEnvironment frais -> load_resolved_logging_config(Some(profile), env) -> into_settings() -> reinitialize(guard, settings) -> succès : mise à jour metadata runtime -> échec : runtime précédent inchangé ``` La sauvegarde ne doit pas déclencher implicitement un reload. Cela permet d'éditer plusieurs profils sans changer le runtime et rend les erreurs/rollback compréhensibles. ### 11.2 Probe contrôlé `run_logging_probe` ne reçoit pas un message de log libre contenant potentiellement un secret. Il émet une petite séquence contrôlée, avec un identifiant unique non sensible retourné à l'UI, par exemple : ```text INFO target=ksp-app-config-desk.probe domain=config-desk DEBUG target=ksp-app-config-desk.probe domain=config-desk WARN target=ksp-app-config-desk.probe domain=config-desk ``` L'UI affiche l'identifiant du probe et rappelle les sinks attendus. La démonstration manuelle peut ainsi vérifier qu'après reload : - un sink apparaît/disparaît ; - un format change ; - un niveau/routing change ; - la console reçoit ou non l'événement ; - un fichier distinct reçoit l'événement correspondant. ### 11.3 Profil invalide Test obligatoire : ```text runtime A valide actif -> tentative apply B invalide -> erreur -> probe suivant toujours routé selon A ``` La réussite de ce scénario ferme le critère « une erreur de nouvelle configuration ne détruit pas le runtime Logging déjà valide ». ## 12. Matrice fonctionnelle de clôture Logging La release ne peut pas être clôturée sans preuve des cas suivants : | Cas | Action UI | Résultat attendu | |-----|-------------------------------|-----------------------------------------------------------------| | L1 | créer un second profil | profil ajouté via types Config et sauvegardable | | L2 | modifier le profil existant | mutation persistée via `save_logging_document()` | | L3 | profil mono-fichier | console optionnelle + exactement un sink fichier valide | | L4 | profil multi-fichiers | au moins deux sinks fichier distincts + sortie logiciel/console | | L5 | sauvegarder sans appliquer | source change, runtime reste inchangé | | L6 | sélectionner/appliquer profil | `load_resolved_logging_config` + `reinitialize` réussissent | | L7 | probe avant/après | changement de routing/format/sink observable sans redémarrage | | L8 | appliquer config invalide | erreur visible, runtime précédent reste fonctionnel | | L9 | redémarrer l'app | profil/default persisté retrouvé selon le document sauvegardé | | L10 | modifier default profile | nouveau `default_profile` validé/persisté par Config | La démonstration de clôture conservera deux profils de test reproductibles, sans dépendre de données secrètes. ## 13. Splashscreen commun ### 13.1 Décision de `0.1.4` `0.1.4` établit la **référence canonique** du lifecycle splash KSP, mais ne crée pas prématurément une nouvelle crate `ksp-tauri-lib` avec un seul consumer. Le splash sera isolé proprement : ```text backend : splash.rs + tw_splash.rs frontend: splash.ts + splash.scss + splash.html ``` Les helpers ne sont pas recopiés entre fenêtres. Lorsque la deuxième application Tauri KSP sera introduite, elle devra réutiliser/extracter cette capacité commune au lieu de copier le code. Si un deuxième consumer apparaît avant la clôture de `0.1.4`, l'extraction en crate/module partagé pourra être avancée par delta explicite. ### 13.2 Configuration Aucune durée sensible à l'environnement n'est codée en dur par application. Le besoin runtime devra au minimum distinguer ce qui est réellement nécessaire, par exemple : ```text minimum display duration fade duration close delay si techniquement distinct ``` La ou les clés Config/.env exactes **ne sont pas figées dans `pre.001`**, conformément à la règle qui demande de les nommer lors de leur première utilisation concrète. Elles devront : - utiliser `KSP_*` ou `KSP_PUBLIC_*` selon exposition ; - être lues uniquement via Config ; - être ajoutées à `.env.example` avec commentaire dans le même delta ; - posséder fallback et bornes de validation ; - être transmises au frontend uniquement si celui-ci a réellement besoin de la valeur. ## 14. Présentation et Markdown Décision explicite : **aucune vue de présentation dans `0.1.4`**. L'application est un manager monofenêtre avec navigation fonctionnelle. En conséquence : ```text PRESENTATION.md : absent markdown-it : absent ``` `README.md` reste la documentation du package et n'est jamais chargé dans une webview. Si une future version ajoute réellement une vue de présentation, elle ouvrira alors le besoin `PRESENTATION.md` + `markdown-it` et appliquera la règle d'absence de liens navigables dans le contenu affiché. ## 15. Extensibilité des futurs `file_id` / schemas / éditeurs L'extensibilité est structurée en trois niveaux. ### 15.1 Shell générique Le shell sait : - demander à Config quels documents sont enregistrés ; - afficher leurs descripteurs ; - demander validation/diagnostic/source ; - afficher les diagnostics sans connaître le schema métier. Il ne code pas la liste `cfg.std.logging` comme unique vérité du système. ### 15.2 Adapter d'éditeur spécialisé Logging est le premier adapter spécialisé : ```text file_id = cfg.std.logging editor = LoggingEditor ``` Le frontend possède une table/registry applicative simple d'éditeurs disponibles, basée sur `file_id`. Un futur document pourra ajouter : ```text file_id -> panel/editor spécialisé ``` sans modifier le moteur générique de liste/diagnostic/source. ### 15.3 Config reste propriétaire Même avec un éditeur spécialisé : ```text DTO UI -> service app -> type public ksp-config-lib -> validation/persistence ksp-config-lib ``` Aucun nouvel éditeur ne reçoit une API de filesystem directe ni ne transporte son propre validateur autoritatif. ## 16. Stratégie de tests ### 16.1 `ksp-config-lib` Pour les deux extensions révélées par l'audit : - unit tests hors `src`, structure miroir ; - tests de registre : ordre, kind, schema, override conservé ; - tests de réparation : JSON invalide refusé, schema invalide refusé, sémantique invalide refusée, source valide atomiquement persistée, path arbitraire impossible ; - test public d'usage depuis `tests/` si le contrat public le justifie. ### 16.2 Rust applicatif Tests ciblés : - conversion sûre `ksp_core_lib::Error` -> diagnostic DTO ; - aucune valeur de contexte sensible recopiée ; - mapping DTO Logging -> contrats Config ; - AppState : metadata runtime ne change qu'après reload réussi ; - policy reveal ; - probe : payload fixe ; - splash settings : bornes et lifecycle ; - single-instance helper lorsque testable sans flakiness. Pendant le développement : ```text cargo test -p ksp-config-lib cargo test -p ksp-app-config-desk ``` selon la tranche. ### 16.3 Frontend Le frontend reste suffisamment mince pour ne pas nécessiter dès le départ un framework de test lourd. Les validations minimum prévues : - `tsc` strict ; - build Vite ; - tests de fonctions pures TypeScript uniquement si une logique non triviale apparaît ; - parcours manuel reproductible des panneaux et de la matrice Logging. Si des fonctions UI critiques deviennent suffisamment complexes, un runner de tests sera ajouté seulement au moment du besoin réel. ### 16.4 Tauri / intégration Les commandes sont testées principalement via leurs services Rust sans lancer une webview. Les points nécessitant Tauri réel sont validés par : - build Tauri ; - lancement `tauri dev` ; - splash -> main ; - single-instance ; - commandes invoke ; - hot reload Logging observable ; - absence de crash après échec de reload. ### 16.5 Frontières globales Après toute modification Rust : ```text cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets ``` Les tests ciblés par package sont privilégiés pendant les tranches. `cargo test --workspace` est obligatoire : - à l'ouverture globale si nécessaire pour confirmer la base ; - à la fermeture finale de `0.1.4` ; - lors d'une tranche transversale qui le justifie explicitement. Les `cargo tree` pertinents seront exécutés après ajout/modification des dépendances Tauri/Config/Logging et à la clôture. Côté frontend, les commandes de build/test retenues seront ajoutées au `package.json` et exécutées dans les tranches concernées. ## 17. Hors scope confirmé `0.1.4` n'ouvre pas : - Wallet ; - Store/PostgreSQL ; - RPC/WS/provider ; - Program/decoder/executor ; - workers/jobs/pipelines ; - trading/ML ; - nouveaux documents Config pour composants inexistants ; - watcher filesystem générique ; - service distribué de configuration ; - secrets manager distant ; - chiffrement maison de `.env` ; - auth biométrique/keychain ; - application de contrôle globale KSP ; - système générique de plugins UI dynamiques chargés à runtime ; - éditeur de JSON Schema ; - viewer de logs complet dans l'UI ; - nouvelle crate partagée Tauri sans deuxième consumer concret. ## 18. Prévision souple des prereleases Chaque tranche vise environ 15–20 minutes de travail effectif. Cette prévision est un ordre de travail, pas un plafond contractuel. ```text pre.001 audit + brainstorming + plan détaillé pre.002 compléter ksp-config-lib pour Config Desk - vue publique du registre - réparation source validée/atomique par file_id - tests + docs Config ciblés pre.003 créer ksp-app-config-desk - membre workspace - Cargo lib+bin/build.rs - package frontend/Vite/TS/SCSS minimal - tauri.conf/capabilities/icône de base - single-instance - plugin tracing Rust sans subscriber propre pre.004 bootstrap backend + AppState - argv -> bootstrap/registry/engine/management - initialisation Logging - fallback sûr si Logging source invalide - LoggingGuard durable - erreurs/DTO communs pre.005 shell main + splash de référence - lifecycle splash - timing via Config/.env - .env.example dans le même delta - navigation monofenêtre - gabarit SCSS/Bootstrap/Font Awesome pre.006 Documents + diagnostics - inventaire générique - catégories d'erreurs - source brut invalide - réparation via Config pre.007 Profils + provenance - default_profile - sélection explicite - global/profile/effective/provenance sûre pre.008 Environnement - rapports desired/effective/shadow - set/remove .env - messages process shadowing pre.009 Secrets privilégiés - DTO séparés - UX confirmation/reveal transitoire - audits non-divulgation pre.010 Logging editor — contrats - DTO typés - profils/console/files/filters - mapping vers types management Config pre.011 Logging editor — opérations/persistence - create/clone/rename/delete profils - default_profile - mono-fichier/multi-fichiers - save_logging_document pre.012 Logging runtime - sélection profil à appliquer - ConfigEnvironment frais - reinitialize - metadata runtime transactionnelle - probe contrôlé pre.013 matrice fonctionnelle Logging - cas mono-fichier - cas multi-fichiers + console - save sans apply - hot reload observable - reload invalide -> ancien runtime conservé pre.014 robustesse desktop/extensibilité - diagnostics invalid source au démarrage - audits secrets/Config ownership/tracing - tests frontend/Tauri/build - vérification ajout futur file_id/editor pre.015 clôture - fmt/check/clippy - tests package + cargo test --workspace - cargo tree pertinents - build frontend/Tauri - README.md + USAGE.md finalisés - aucun PRESENTATION.md - TODO fermés/reportés - documentation/changelog/prompt suivant - préparation rel.001 ``` Une tranche qui dépasse clairement le budget sera scindée plutôt que comprimée. Un défaut livré est corrigé par un `fix` conformément au workflow KSP. ## 19. Dépendances et ordre d'introduction Aucune dépendance n'est ajoutée par `pre.001`. Ordre candidat : ### Rust desktop ```text tauri tauri-build tauri-plugin-tracing fs2 ts-rs ``` `serde` / `serde_json` existent déjà dans le workspace et seront réutilisés si nécessaires aux DTO. Les dépendances Rust desktop destinées à être réutilisables par les futures applications (`tauri`, `tauri-build`, `tauri-plugin-tracing`, `fs2`, `ts-rs`) seront versionnées au `Cargo.toml` racine sous `[workspace.dependencies]` puis consommées avec `.workspace = true` ; aucune version externe partagée ne sera dupliquée dans la crate applicative. `tokio` n'est pas automatiquement promu à `full`. Les features nécessaires au splash seront choisies au besoin réel. Aucun `rustls` direct n'est ajouté par symétrie avec bot3. ### Frontend ```text @tauri-apps/api @tauri-apps/cli vite typescript sass-embedded bootstrap @fortawesome/fontawesome-free ``` `@types/node` ne sera ajouté que si la configuration Vite TypeScript en a réellement besoin. Les autres packages bot3 sont exclus tant qu'une tranche n'en démontre pas l'usage immédiat. La politique KSP sans lockfile versionné reste inchangée. ## 20. Critères de validation de la release `0.1.4` peut être considérée fonctionnellement complète seulement si tous les critères suivants sont vrais : ### Architecture - la crate est directement sous `crates/` ; - lib+bin séparés, `main.rs` mince, `lib.rs` déclaratif ; - toutes les commandes Tauri sont dans `tauri.rs` ; - services/modules métier hors wrappers ; - aucune lecture/écriture directe des fichiers Config/`.env` ; - aucune lecture `std::env::var*` pour KSP/KSPB hors Config ; - aucun `tauri-plugin-log` ; - aucun subscriber tracing parallèle ; - plugin tracing intégré sans `with_default_subscriber()` ; - Logging runtime possédé par `ksp-logging-lib`. ### Documents/profils - documents enregistrés listés depuis Config ; - source invalide inspectable et réparable sans filesystem direct ; - erreurs JSON/schema/sémantiques/effective distinguées ; - `default_profile` et profils inspectables ; - source/global/profile/effective montrés lorsque pertinent. ### Environnement/secrets - rapports desired/effective/source/shadow fonctionnels ; - set/remove `.env` via Config ; - shadow process expliqué ; - safe values par défaut ; - reveal séparé et explicite ; - aucune valeur Secret réelle dans logs/diagnostics/snapshot/state persistant. ### Logging - plusieurs profils créables/modifiables ; - profil mono-fichier démontré ; - profil multi-fichiers + console démontré ; - sauvegarde fonctionnelle ; - profil sélectionnable/appliquable ; - hot reload observable sans redémarrage ; - probe contrôlé ; - échec reload laisse ancien runtime actif. ### Extensibilité - shell Documents non codé uniquement autour de Logging ; - registre Config reste source de vérité des `file_id` ; - Logging est un éditeur spécialisé branché sur un shell générique ; - ajout futur d'un `file_id` ne demande pas de réécrire bootstrap/diagnostics/persistence. ## 21. Documentation finale attendue À la clôture : ```text crates/ksp-app-config-desk/README.md crates/ksp-app-config-desk/USAGE.md ``` `README.md` décrit le rôle, l'architecture, les dépendances et les frontières de sécurité. `USAGE.md` décrit : - lancement/arguments bootstrap ; - splash ; - fenêtre principale ; - panneau Documents ; - panneau Profils ; - panneau Environnement ; - reveal secrets ; - panneau Logging ; - sauvegarde/application ; - probe/hot reload ; - diagnostics usuels. Il n'y aura pas de `PRESENTATION.md` dans `0.1.4` tant qu'aucune vue de présentation n'existe. ## 22. Questions ouvertes volontairement reportées à leur tranche Aucune question n'empêche d'ouvrir le développement après validation du présent plan. Les choix suivants seront figés au moment où l'implémentation fournit les contraintes réelles : 1. nom public exact des deux petites extensions Config (`descriptors`/inventaire et sauvegarde de source candidate) ; 2. nom exact et nombre minimal de variables splash Config/.env ; 3. features Cargo minimales de Tauri/Tokio nécessaires au shell/splash ; 4. détails du fallback Logging minimal utilisé uniquement lorsque la Config Logging ne peut pas être résolue au démarrage ; 5. possibilité d'exploiter une évolution future de `tauri-plugin-tracing` permettant un target JS namespacé `ksp-*` sans affaiblir Logging. Ces points doivent être résolus par code/tests dans les prereleases prévues, pas par contournement applicatif.