diff --git a/Cargo.toml b/Cargo.toml index ce66a8d..bc30003 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 25 +# version: 26 [workspace] resolver = "3" members = ["crates/ksp-core-lib"] [workspace.package] -version = "0.1.1" +version = "0.1.2-pre.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/ROADMAP.md b/ROADMAP.md index 0f77c60..3235ac3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,5 @@ - + # Roadmap KSP @@ -32,7 +32,7 @@ Regrouper les releases consacrées aux fondations N1. Chaque release concrète e ### Releases concrètes - [X] `0.1.1` — Stabiliser `ksp-core-lib` : `Error`/`Result`, Program IDs fondamentaux et primitives réellement N1. -- [ ] `0.1.2` — Introduire `ksp-logging-lib` comme façade KSP de `tracing`, `tracing-appender` et `tracing-subscriber`. +- [/] `0.1.2` — Introduire `ksp-logging-lib` comme façade KSP de `tracing`, `tracing-appender` et `tracing-subscriber`. - [ ] `0.1.3` — Introduire `ksp-config-lib` : documents, profils, résolution, validation et modifications autorisées. - [ ] `0.1.4` — Introduire `ksp-app-config-desk` pour valider réellement Config et la frontière Tauri. diff --git a/deltas/0.1.2/pre.001.md b/deltas/0.1.2/pre.001.md new file mode 100644 index 0000000..5478580 --- /dev/null +++ b/deltas/0.1.2/pre.001.md @@ -0,0 +1,375 @@ + + + +# Delta 0.1.2-pre.001 + +## Base requise + +Release stable/taguée attendue : + +```text +v0.1.1 +``` + +L'archive Gitea fournie `khadhroony-solana-project-v0.1.1.zip` contient bien : + +- `workspace.package.version = "0.1.1"` ; +- le delta final `deltas/0.1.1/rel.001.md` ; +- le prompt final `prompts/002-V0_1_2_START_PROMPT.md` ; +- la surface Core stabilisée attendue. + +Dans le workflow KSP, cette archive provient directement du tag correspondant et constitue la base stable suffisante pour ouvrir `0.1.2`. + +## Objectif + +Ouvrir `0.1.2` par la prerelease obligatoire de brainstorming, audit et planification, sans développement fonctionnel Logging. + +Cette tranche : + +- inventorie l'état réel du workspace et confirme l'absence actuelle de `ksp-logging-lib` ; +- audite la stack `tracing` officielle actuelle ; +- fixe la frontière façade/instrumentation/runtime subscriber ; +- retient les macros KSP pour préserver les callsites ; +- définit les niveaux et settings runtime candidats ; +- borne la sémantique de `target`, `domain` et `component` ; +- retient le filtering global + target-prefix via `Targets` ; +- retient console + fichier optionnel ; +- retient un writer fichier non bloquant non-lossy avec guard possédé explicitement ; +- définit le lifecycle d'initialisation/réinitialisation ; +- fixe la stratégie d'erreurs Core et de protection des secrets ; +- dimensionne `pre.002` à `pre.006` ; +- confirme les hors-scope. + +Le détail est consigné dans `docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md`. + +## Version Cargo + +`workspace.package.version` passe de : + +```text +0.1.1 +``` + +à : + +```text +0.1.2-pre.1 +``` + +L'identifiant Cargo respecte SemVer sans zéro initial ; l'identifiant de livraison reste `0.1.2-pre.001`. + +Le header de `Cargo.toml` passe de version 25 à 26. + +Aucune dépendance `tracing*` n'est ajoutée par cette tranche de planification : elles seront introduites uniquement lorsque le code/tests de `ksp-logging-lib` les consommeront réellement. + +## Fichiers ajoutés + +- `docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md` +- `deltas/0.1.2/pre.001.md` + +## Fichiers modifiés + +- `Cargo.toml` +- `ROADMAP.md` +- `docs/plans/000-README.md` + +## Fichiers supprimés + +Aucun. + +## Inventaire du workspace + +État de la base stable auditée : + +```text +workspace members +└── crates/ksp-core-lib +``` + +`ksp-logging-lib` n'existe pas encore. + +Core fournit déjà les contrats nécessaires à Logging : + +```text +ksp_core_lib::ErrorCode +ksp_core_lib::ErrorContext +ksp_core_lib::Error +ksp_core_lib::Result +ksp_core_lib::Pubkey +``` + +ainsi que les Program IDs fondamentaux et leur registre descriptif. + +La relation retenue reste unidirectionnelle : + +```text +ksp-logging-lib -> ksp-core-lib +ksp-core-lib -X-> ksp-logging-lib +``` + +## Audit externe tracing + +Audit effectué le 2026-08-14 sur les publications/docs officielles Tokio `tracing`, docs.rs/crates.io et les manifests publiés. + +Versions observées : + +```text +tracing 0.1.44 rustc 1.65+ +tracing-subscriber 0.3.23 rustc 1.65+ +tracing-appender 0.2.5 rustc 1.63+ +``` + +Contraintes candidates à revérifier au moment de l'ajout effectif : + +```toml +tracing = { version = "^0.1", default-features = false, features = ["std"] } +tracing-subscriber = { version = "^0.3", default-features = false, features = ["fmt"] } +tracing-appender = { version = "^0.2", default-features = false } +``` + +Décisions de features : + +- pas de `tracing-attributes`/`attributes` ; +- pas de `ansi` ; +- pas de `tracing-log` ; +- pas d'`env-filter` ; +- pas de JSON/Serde ; +- pas de chrono/time formatter via `tracing-subscriber` ; +- pas de `parking_lot` appender ; +- `tracing-appender` tire lui-même `tracing-subscriber` avec `default-features = false`, `fmt` et `std` ainsi que les dépendances internes nécessaires à son fonctionnement. + +Aucune dépendance n'est ajoutée uniquement parce qu'elle figure dans l'architecture candidate. + +## Décisions de planification + +### Façade et callsites + +La surface d'émission KSP sera : + +```text +ksp_logging_lib::error! +ksp_logging_lib::warn! +ksp_logging_lib::info! +ksp_logging_lib::debug! +ksp_logging_lib::trace! +``` + +Les événements ne seront pas émis par de simples fonctions wrappers qui déplaceraient les métadonnées source. + +L'implémentation exacte des macros doit réussir un test d'intégration prouvant que file/module/line et target implicite restent ceux du consommateur. + +### Champs structurés + +- `target` : métadonnée native de routage/filtering, naturelle au callsite ou explicitement overridable ; +- `domain` : champ structuré KSP optionnel ; +- `component` : champ structuré KSP optionnel ; +- autres champs : ouverts selon besoin, sans taxonomie fermée. + +`domain` et `component` ne deviennent pas des filtres dans `0.1.2`. + +### Filtering + +Première surface : + +```text +default filter level ++ zero or more target-prefix overrides +``` + +`tracing_subscriber::filter::Targets` est retenu comme mécanisme initial. + +`EnvFilter`, `RUST_LOG`, field-based filtering et hot reload restent hors scope. + +### Settings runtime + +Surface conceptuelle retenue : + +```text +LogFilterLevel +TargetFilter +ConsoleOutput +ConsoleSettings +FileRotation +FileSettings +LoggingSettings +LoggingGuard +initialize(...) +``` + +Les settings ne lisent ni fichier, ni environnement, ni profil Config et ne contiennent aucun secret. + +### Console + +Sortie console avec choix explicite stdout/stderr. + +Le formatter initial reste humain, sans JSON ni ANSI obligatoire. + +### Fichier + +Sortie fichier optionnelle retenue avec : + +```text +Never | Hourly | Daily +``` + +Le builder fallible du `RollingFileAppender` doit être utilisé afin de remonter les erreurs au lieu de paniquer. + +Le writer fichier utilise `NonBlockingBuilder` en mode : + +```text +lossy(false) +``` + +La saturation applique donc de la backpressure plutôt que de supprimer silencieusement des logs. + +### Lifecycle + +`LoggingGuard` possède le ou les `WorkerGuard` nécessaires au backend non bloquant. + +L'appelant conserve le guard jusqu'à la fin ordonnée du processus. + +Le lifecycle global est volontairement : + +```text +uninitialized -> initialized -> process shutdown +``` + +Une initialisation répétée échoue avec une erreur KSP ; elle ne remplace pas silencieusement un subscriber existant et ne panique pas. + +### Erreurs + +Les erreurs Logging utilisent le contrat Core et restent dans le domaine : + +```text +logging +``` + +Codes conceptuels initiaux : + +```text +logging.invalid_settings +logging.already_initialized +logging.file_output_initialization_failed +``` + +Les causes externes utiles sont conservées via `Error::with_source(...)` lorsque possible. + +### Secrets + +Sont explicitement interdits dans les logs : clés privées, seeds/mnemonics, passwords/passphrases/PIN, tokens API/bearer/session, cookies/auth headers, secrets de chiffrement/signature, credentials de connexion et futurs `*_SECRET_*`. + +Aucun helper de redaction universel n'est introduit : le caller doit omettre ou redacter explicitement la valeur avant émission. + +Les settings Logging ne contiennent eux-mêmes aucun secret. + +### Surface différée + +Ne pas ajouter dans `0.1.2` sans nouveau besoin validé : + +- spans KSP/`#[instrument]` ; +- OpenTelemetry ; +- JSON ; +- ANSI ; +- compatibilité `log` ; +- `EnvFilter` ; +- reload de filtre ; +- filtering par fields/domain ; +- rotation minutely/weekly/by-size ; +- compression/rétention complexe/latest symlink ; +- routes multiples avancées. + +## Référence historique bot3 + +L'ancien `ks-logging` de l'archive bot3 fournie a été relu comme référence historique uniquement. + +Éléments conservés comme leçons utiles : + +- objet de lifecycle possédant les `WorkerGuard` ; +- console + fichier ; +- rotation ; +- filtering par targets. + +Éléments non migrés : + +- dépendance Logging -> Config ; +- document/schema JSON propre à Logging ; +- Serde/JSON pour la configuration ; +- routes/formats multiples non nécessaires à la première surface KSP. + +## Prereleases prévues + +```text +pre.001 audit + brainstorming + plan +pre.002 crate + settings + macros/façade +pre.003 subscriber + console + filtering + callsite final +pre.004 fichier + non-blocking + lifecycle +pre.005 intégration + tests + audits +pre.006 validation finale + docs/cleanup + prompt 0.1.3 +``` + +Le découpage reste souple ; une tranche trop large sera scindée plutôt que surchargée. + +## Hors scope confirmé + +- Config/documents/profils ; +- Tauri ; +- Wallet/signing ; +- RPC/WS/providers ; +- Program decoding/execution ; +- Store/PostgreSQL ; +- Materializer ; +- workers/jobs/pipelines ; +- scenarios ; +- trading/ML ; +- observabilité distribuée/OpenTelemetry. + +## Validations exécutées + +Dans l'environnement de préparation de ce delta : + +- lecture/audit de l'archive complète `0.1.1` fournie ; +- vérification statique de `workspace.package.version = "0.1.1"` ; +- vérification de la présence du delta `0.1.1/rel.001` et du prompt final `0.1.2` ; +- inventaire des membres workspace et confirmation de l'absence de `ksp-logging-lib` ; +- lecture des règles, plans, indexes et documents d'architecture demandés par le prompt ; +- lecture de `ksp-core-lib` et de son contrat Error/Result ; +- audit de l'ancien `ks-logging` bot3 fourni comme référence historique, sans le traiter comme source de vérité KSP ; +- vérification des versions/features/MSRV actuels de `tracing`, `tracing-subscriber` et `tracing-appender` depuis leurs sources de publication officielles ; +- audit du manifest publié de `tracing-appender` pour ses dépendances/features ; +- audit de `Targets`, `EnvFilter`, du non-blocking, du mode lossy/backpressure, de `WorkerGuard`, du builder fallible et de la rotation ; +- parsing TOML statique du manifest modifié ; +- contrôle statique des headers `file:` / `version:` des fichiers ajoutés/modifiés ; +- contrôle statique des liens Markdown locaux après modification ; +- contrôle du contenu de l'archive delta selon `VER-ARCHIVE-004`. + +## Validations non exécutées + +L'environnement de préparation ne contient ni `cargo` ni `rustc`. + +Les commandes suivantes n'ont donc pas pu être exécutées ici : + +```bash +cargo fmt --all +cargo check --workspace +cargo test --workspace +cargo clippy --workspace --all-targets +cargo tree -p ksp-logging-lib +cargo tree -p ksp-logging-lib -d +cargo tree -p ksp-logging-lib -e features +``` + +Les trois commandes `cargo tree -p ksp-logging-lib` ne sont de toute façon applicables qu'après création effective de la crate. + +Aucun succès Cargo n'est déclaré par ce delta. + +## Questions ouvertes + +Aucune question architecturale bloquante ne justifie de poursuivre le développement dans `pre.001`. + +À confirmer par tests dans les tranches suivantes : + +- mécanisme exact de macro KSP préservant le callsite avec la plus petite surface ; +- format visuel exact des lignes humaines sans le figer comme protocole ; +- nécessité future de capacités volontairement différées comme rétention, ANSI, JSON, `tracing-log`, `EnvFilter`, spans ou reload. + +La prochaine tranche après validation de ce plan est `0.1.2-pre.002`. diff --git a/docs/plans/000-README.md b/docs/plans/000-README.md index e9bf44f..4190671 100644 --- a/docs/plans/000-README.md +++ b/docs/plans/000-README.md @@ -1,5 +1,5 @@ - + # Plans KSP @@ -12,6 +12,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou - [`001-V0_0_3_PLAN.md`](001-V0_0_3_PLAN.md) — plan historique de la phase fondatrice `0.0.3`, clôturée ; - [`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 actif de la release `0.1.2` Logging foundation, établi par `0.1.2-pre.001`. Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre. diff --git a/docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md b/docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md new file mode 100644 index 0000000..e2aa151 --- /dev/null +++ b/docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md @@ -0,0 +1,869 @@ + + + +# Plan KSP 0.1.2 — Logging foundation + +## Statut + +Plan actif de `0.1.2`, établi par `0.1.2-pre.001`. + +`pre.001` reste une tranche de brainstorming, audit et planification. Aucun développement fonctionnel de `ksp-logging-lib` n'est commencé avant validation de ce plan. + +## Base auditée + +Base fournie : + +```text +0.1.1 stable +``` + +Constats sur l'archive `khadhroony-solana-project-v0.1.1.zip` reçue : + +- `workspace.package.version = "0.1.1"` ; +- le workspace contient uniquement `crates/ksp-core-lib` ; +- `ksp-logging-lib` n'existe pas encore ; +- `ksp-core-lib` expose déjà `ErrorCode`, `ErrorContext`, `Error`, `Result` et `Pubkey` ainsi que les Program IDs fondamentaux et leur registre ; +- `ksp-core-lib` dépend uniquement de `solana-pubkey` au runtime ; +- le delta final `deltas/0.1.1/rel.001.md` enregistre la validation finale de `0.1.1` ; +- le prompt `prompts/002-V0_1_2_START_PROMPT.md` présent dans la base ouvre bien la release Logging. + +Dans le workflow KSP, l'archive fournie provient directement du tag Gitea correspondant et constitue la base stable/taguée `v0.1.1` attendue. L'absence normale de `.git` dans l'archive ne crée pas une vérification Git supplémentaire pour cette session. + +## Mission bornée + +`0.1.2` introduit `ksp-logging-lib` comme façade KSP commune de logging/tracing et propriétaire de la politique runtime correspondante. + +La release doit fournir : + +1. une surface d'émission KSP pour `error`, `warn`, `info`, `debug` et `trace` ; +2. des settings runtime propres à Logging, indépendants de Config ; +3. une initialisation globale déterministe ; +4. une sortie console ; +5. une sortie fichier optionnelle avec rotation bornée et writer non bloquant ; +6. un filtrage global et par préfixe de `target` ; +7. un lifecycle explicite conservant les guards nécessaires aux writers non bloquants ; +8. un contrat d'erreurs basé sur `ksp-core-lib` ; +9. une politique documentée contre les fuites de secrets ; +10. les tests de callsite, settings, filtering, initialisation, fichiers et façade publique nécessaires à la stabilisation. + +La release ne lit aucun document JSON/TOML et n'introduit aucune dépendance vers Config ou une couche supérieure. + +## Frontière de propriété + +La frontière retenue reste : + +```text +ksp-logging-lib + -> ksp-core-lib + -> tracing + -> tracing-subscriber + -> tracing-appender +``` + +Règles : + +- `ksp-logging-lib` est le seul propriétaire KSP de l'initialisation et de la politique de subscriber/appender ; +- `ksp-core-lib` ne dépend pas de Logging ; +- `ksp-logging-lib` ne dépend pas de `ksp-config-lib` ; +- `ksp-logging-lib` ne dépend pas de Wallet, Transport, Program, Store, workers, jobs, pipelines ou applications ; +- les crates comportementales KSP peuvent plus tard dépendre directement de `ksp-logging-lib` ; +- les crates `*-api` purement déclaratives restent sans Logging par défaut ; +- une future intégration Tauri imposée par un plugin reste un adaptateur d'application et ne redéfinit pas la politique KSP. + +## Audit de la stack `tracing` au 2026-08-14 + +L'audit a été réalisé à partir des publications/docs officielles Tokio `tracing` et des manifests publiés sur docs.rs/crates.io. + +### Versions observées + +```text +tracing 0.1.44 MSRV annoncé : rustc 1.65+ +tracing-subscriber 0.3.23 MSRV annoncé : rustc 1.65+ +tracing-appender 0.2.5 MSRV annoncé : rustc 1.63+ +``` + +Ces exigences restent inférieures au MSRV déjà imposé indirectement par la génération Solana retenue dans `0.1.1` (`solana-pubkey 4.3.0` / workspace Solana SDK auditée à Rust 1.89.0). Logging ne relève donc pas le plancher observé du workspace. + +Les versions doivent néanmoins être revérifiées au moment exact de leur ajout effectif au manifest. + +### `tracing` + +`tracing 0.1.44` active par défaut `attributes` et `std` ; la feature `attributes` tire `tracing-attributes`. + +La première surface KSP n'utilise ni `#[instrument]` ni autre macro attribut procédurale. La dépendance candidate est donc : + +```toml +tracing = { version = "^0.1", default-features = false, features = ["std"] } +``` + +Aucune feature `attributes`, `log`, `valuable` ou filtre compile-time n'est activée par anticipation. + +### `tracing-subscriber` + +`tracing-subscriber 0.3.23` active par défaut notamment `ansi`, `fmt`, `smallvec`, `std` et `tracing-log`. + +La première surface KSP a besoin de `fmt`, qui entraîne déjà `registry` et `std`. Elle n'a pas de besoin concret pour : + +- `ansi` ; +- `tracing-log` ; +- `env-filter` ; +- `json` ; +- `chrono` ; +- `time` ; +- `local-time` ; +- `serde` ; +- `parking_lot`. + +La dépendance candidate est donc : + +```toml +tracing-subscriber = { version = "^0.3", default-features = false, features = ["fmt"] } +``` + +Le filtrage initial utilisera `tracing_subscriber::filter::Targets`, disponible sans `env-filter` et conçu pour les niveaux par préfixe de target. + +### `tracing-appender` + +`tracing-appender 0.2.5` n'active aucune feature par défaut et ne propose qu'une feature optionnelle `parking_lot`. + +Son manifest publié dépend déjà de `tracing-subscriber` avec `default-features = false` et `features = ["fmt", "std"]`. Il tire également les dépendances nécessaires à son appender, notamment `crossbeam-channel`, `time`, `symlink` et `thiserror`. + +Aucun besoin de `parking_lot` n'est identifié. + +La dépendance candidate est donc : + +```toml +tracing-appender = { version = "^0.2", default-features = false } +``` + +### Politique d'ajout au manifest + +Aucune de ces trois dépendances n'est ajoutée par `pre.001`, car aucun code de `ksp-logging-lib` ne les consomme encore. + +Elles seront ajoutées sous `[workspace.dependencies]` uniquement dans la prerelease qui les utilise effectivement, puis héritées dans `crates/ksp-logging-lib/Cargo.toml` avec `.workspace = true`. + +Après chaque ajout réel : + +```bash +cargo tree -p ksp-logging-lib +cargo tree -p ksp-logging-lib -d +cargo tree -p ksp-logging-lib -e features +``` + +sera utilisé pour vérifier la résolution et l'unification réelles. + +## Instrumentation : macros pour préserver le callsite + +### Décision + +Les cinq points d'émission publics seront des macros KSP : + +```text +ksp_logging_lib::error! +ksp_logging_lib::warn! +ksp_logging_lib::info! +ksp_logging_lib::debug! +ksp_logging_lib::trace! +``` + +Une fonction wrapper qui appellerait elle-même `tracing::info!` ou équivalent déplacerait les métadonnées source vers le wrapper. Les événements ne seront donc pas émis par des fonctions publiques de ce type. + +Les macros KSP resteront minces et délégueront aux macros `tracing` au point d'appel. Leur implémentation exacte — wrapper `macro_rules!` transparent ou réexport suffisamment direct — sera choisie par le plus petit mécanisme qui réussit les tests de callsite sans exposer une seconde API `tracing` aux consommateurs. + +### Syntaxe + +La surface doit conserver une syntaxe structurée proche de `tracing` plutôt que créer une grammaire KSP parallèle. + +Exemple conceptuel : + +```rust +ksp_logging_lib::info!( + target: "ksp.wallet", + domain = "wallet", + component = "repository", + slot = slot, + "wallet state updated" +); +``` + +Les tests publics fixeront uniquement la syntaxe réellement retenue avant stabilisation. + +### Callsite à tester + +Un test d'intégration extérieur au `src` doit capturer les `Metadata` d'un événement émis par une macro KSP et vérifier au minimum : + +- le fichier source est celui du consommateur/test et non un fichier de `ksp-logging-lib` ; +- le module path correspond au consommateur ; +- le numéro de ligne correspond à l'invocation ; +- le target implicite reste celui du callsite/module lorsque le caller n'en fournit pas ; +- un `target:` explicite est conservé tel quel. + +La macro n'est pas considérée stabilisée avant réussite de ce test. + +## Niveaux KSP + +Les cinq niveaux d'événements publics sont exactement : + +```text +error +warn +info +debug +trace +``` + +Ils correspondent aux niveaux homonymes de `tracing`. + +Le filtrage a en plus besoin d'un état désactivé. Le plan prévoit un type KSP distinct, conceptuellement : + +```text +LogFilterLevel + Off + Error + Warn + Info + Debug + Trace +``` + +`Off` n'est pas un sixième niveau d'événement ; il appartient uniquement au contrat de filtering. + +Aucun type `tracing::Level` ou `tracing_subscriber::filter::LevelFilter` n'est exposé dans l'API publique KSP. + +## `target`, `domain`, `component` et champs structurés + +### `target` + +`target` reste la métadonnée native de routage/filtering de `tracing`. + +Politique initiale : + +- sans override, conserver le target naturel correspondant au module/callsite Rust ; +- permettre un `target:` statique explicite lorsque le caller a besoin d'une identité de routage durable ; +- ne pas imposer dès `0.1.2` une taxonomie globale de targets pour toutes les futures crates ; +- filtrer les targets par préfixe. + +### `domain` + +`domain` est un **champ structuré KSP optionnel** décrivant le domaine fonctionnel lorsque cette information ajoute de la valeur. + +Il n'est pas automatiquement injecté et n'est pas une clé de filtrage dans la première surface. + +### `component` + +`component` est un **champ structuré KSP optionnel** décrivant le composant logique à l'intérieur d'un domaine lorsque nécessaire. + +Il n'est ni obligatoire ni déduit du nom de crate. + +### Autres champs + +Les callers peuvent émettre d'autres champs structurés utiles au contexte : slot, signature publique, Program ID public, opération, état, compteur, durée, etc., sous réserve de la politique secrets. + +Aucune liste fermée de champs n'est introduite. + +## Filtering retenu + +### Première surface + +Le filtering initial comprend : + +1. un niveau global/default ; +2. zéro ou plusieurs overrides par préfixe de target. + +Exemple conceptuel : + +```text +default = Info +ksp_program_lib = Debug +ksp_program_lib::decoder = Trace +noisy_dependency = Off +``` + +La sémantique s'appuiera sur `tracing_subscriber::filter::Targets`. + +### Pourquoi pas `EnvFilter` + +`EnvFilter` permet une syntaxe et un filtrage plus dynamiques, notamment par span/champs, mais active des dépendances/features supplémentaires (`matchers`, `regex-automata`, `once_cell`, etc.). + +Aucun besoin de cette puissance n'est démontré pour la fondation `0.1.2`. + +Conséquences : + +- pas de parsing de `RUST_LOG` par Logging ; +- pas de directive textuelle `EnvFilter` dans les settings ; +- pas de filtre sur `domain`/`component` en tant que champs ; +- pas de reload dynamique du filtre dans cette release. + +Config pourra ultérieurement convertir sa propre représentation validée vers les settings typés de Logging sans rendre `EnvFilter` public. + +## Settings runtime + +### Principes + +Les settings appartiennent à `ksp-logging-lib` et représentent uniquement ce dont son runtime a besoin. + +Ils ne : + +- lisent aucun fichier ; +- ne consultent aucune variable d'environnement ; +- ne connaissent aucun profil Config ; +- ne contiennent aucun secret ; +- n'exposent aucun type `tracing*` public. + +Les structures publiques utilisent des champs privés avec constructeurs/getters/builder methods explicites, conformément à la direction déjà utilisée dans Core. + +### Surface conceptuelle + +La surface de `pre.002`/`pre.003` doit rester proche de : + +```text +LoggingSettings + default_filter: LogFilterLevel + target_filters: Vec + console: Option + file: Option + +TargetFilter + target_prefix: String + level: LogFilterLevel + +ConsoleSettings + output: ConsoleOutput + +ConsoleOutput + Stdout + Stderr + +FileSettings + directory: PathBuf + file_name_prefix: String + rotation: FileRotation + +FileRotation + Never + Hourly + Daily +``` + +Les noms exacts peuvent être ajustés pendant l'implémentation uniquement pour respecter l'ergonomie Rust et les règles du dépôt ; les responsabilités ne doivent pas dériver sans correction du plan. + +### Defaults + +Aucun `Default` implicite de `LoggingSettings` n'est requis dans la première surface. + +Le caller choisit explicitement son niveau global et ses sorties. Cela évite qu'une application obtienne silencieusement une politique de production non décidée. + +`ConsoleSettings` pourra offrir des constructeurs explicites `stdout()` / `stderr()` si cela simplifie l'API sans ambiguïté. + +### Validation + +`initialize()` doit refuser au minimum : + +- une configuration sans aucune sortie active ; +- un préfixe de target vide lorsqu'il est fourni comme override ; +- un préfixe de fichier vide si le backend retenu ne peut pas le traiter sans ambiguïté. + +Les autres invariants seront ajoutés uniquement s'ils correspondent à une erreur réelle du backend ou à une ambiguïté de contrat. + +## Console + +La première surface retient une sortie console synchrone via le writer standard choisi : + +```text +Stdout +Stderr +``` + +Raisons : + +- aucune thread dédiée n'est nécessaire pour le terminal dans la première fondation ; +- l'ownership de `WorkerGuard` reste alors réservé à la sortie fichier non bloquante ; +- stdout reste disponible pour les applications qui le souhaitent ; +- stderr permet aux futurs exécutables de ne pas mélanger diagnostics et sortie de données sur stdout. + +Le format initial est un format humain unique, sans JSON ni ANSI obligatoire. Il doit inclure au minimum : + +- timestamp fourni par le formatter standard retenu ; +- niveau ; +- target ; +- message/champs structurés ; +- source file/line lorsque la configuration `fmt` retenue le permet sans dépendance supplémentaire. + +Le texte exact d'une ligne n'est pas un protocole de sérialisation stable. Les tests doivent contrôler les informations nécessaires, pas figer inutilement tous les espaces/ponctuations du formatter externe. + +## Fichiers, rotation et writer non bloquant + +### Capacité retenue + +`0.1.2` retient une sortie fichier **optionnelle** afin que les futurs exécutables/workers disposent d'un backend durable sans réinventer cette responsabilité hors de Logging. + +La première surface reste volontairement étroite : + +```text +rotation = Never | Hourly | Daily +``` + +Sont différés : + +- rotation minutely/weekly ; +- rotation par taille ; +- compression ; +- politique complexe de rétention ; +- symlink `latest` ; +- multiples routes fichier indépendantes ; +- formats fichier distincts par route. + +Une limite de rétention pourra être ajoutée ultérieurement si l'exploitation réelle le justifie ; elle ne fait pas partie du contrat `0.1.2`. + +### Construction sans panic + +L'implémentation doit utiliser la forme builder de `RollingFileAppender` qui retourne un `Result` en cas d'échec d'initialisation, et non une API qui panique. + +L'erreur externe utile est enveloppée dans `ksp_core_lib::Error` et conservée comme `source` lorsque ses bornes le permettent. + +### Non-blocking + +La sortie fichier utilise `tracing_appender::non_blocking::NonBlockingBuilder` afin de déplacer les écritures ordinaires hors du thread appelant. + +Le mode retenu pour la première surface est **non-lossy** : + +```text +lossy(false) +``` + +Ainsi, une saturation de la file applique de la backpressure au lieu de supprimer silencieusement des événements. Cette décision évite d'introduire immédiatement un compteur de lignes perdues et rend le comportement de fiabilité explicite. + +La taille de file reste celle du backend tant qu'un besoin réel ne justifie pas de l'exposer dans `LoggingSettings`. + +Si les mesures futures démontrent que cette backpressure est inacceptable pour certains workloads, un mode lossy explicite et observable pourra être ajouté dans une release ultérieure ; il ne doit pas être activé silencieusement. + +## Lifecycle et ownership du guard + +`tracing-appender` retourne un `WorkerGuard` dont la durée de vie contrôle le flush de la file non bloquante. + +KSP possédera ce guard dans un type public de lifecycle : + +```text +LoggingGuard +``` + +Contrat : + +- `initialize(&LoggingSettings) -> ksp_core_lib::Result` ; +- si seule la console est active, `LoggingGuard` reste un objet valide sans worker fichier ; +- si le fichier est actif, le guard interne est conservé pendant toute la durée de vie de `LoggingGuard` ; +- l'appelant conserve `LoggingGuard` jusqu'à la fin ordonnée du processus ; +- sa destruction effectue le flush/shutdown fourni par le `WorkerGuard` ; +- aucun `WorkerGuard` n'est stocké dans une variable locale d'initialisation qui serait détruite au retour de `initialize()` ; +- aucune fuite volontaire (`mem::forget`, global mutable caché, etc.) n'est utilisée pour prolonger sa durée de vie. + +Le subscriber global de `tracing` n'est pas désinstallable/restartable comme un service ordinaire. Le lifecycle de `0.1.2` est donc volontairement à sens unique : + +```text +uninitialized -> initialized -> process shutdown +``` + +Une destruction anticipée de `LoggingGuard` est considérée comme une fin du backend fichier, pas comme une possibilité de réinitialiser Logging ensuite. + +## Initialisation globale + +### API + +La fonction publique principale retenue est conceptuellement : + +```rust +pub fn initialize(settings: &LoggingSettings) -> ksp_core_lib::Result +``` + +Elle reste synchrone : installer un subscriber et construire des writers locaux ne constitue pas un workflow I/O async justifiant artificiellement une API `async`. + +### Réinitialisation + +L'installation globale doit utiliser une API fallible (`try_init`/équivalent), jamais `init()` lorsqu'elle peut paniquer. + +Comportement : + +- premier appel valide avec subscriber global libre : succès ; +- second appel après succès : erreur KSP déterministe ; +- appel lorsqu'un autre subscriber global a déjà été installé : erreur KSP ; +- aucune tentative silencieuse de remplacer le subscriber existant ; +- aucune comparaison complexe de settings pour rendre un second appel « idempotent » ; +- aucune reconfiguration globale dynamique dans `0.1.2`. + +Les tests globaux doivent éviter de se gêner entre eux, par exemple en isolant la validation de l'initialisation globale dans un test/processus dédié et en testant les composants internes avec des subscribers locaux lorsque possible. + +## Erreurs Logging + +Logging utilise : + +```text +ksp_core_lib::Error +ksp_core_lib::ErrorCode +ksp_core_lib::Result +``` + +Le domaine stable appartient à Logging : + +```text +logging +``` + +Premiers codes conceptuels : + +```text +logging.invalid_settings +logging.already_initialized +logging.file_output_initialization_failed +``` + +Un code supplémentaire n'est ajouté que si une erreur réellement distincte apparaît pendant l'implémentation. + +Règles : + +- les constantes `ErrorCode` sont définies dans `ksp-logging-lib` ; +- Core n'ajoute aucune variante/connaissance Logging ; +- les causes externes utiles sont conservées avec `Error::with_source(...)` lorsqu'elles satisfont `Error + Send + Sync + 'static` ; +- le contexte n'embarque aucun secret ; +- aucun `unwrap`, `expect`, `panic` production ni opérateur `?` n'est introduit. + +## Politique secrets et données sensibles + +### Valeurs interdites dans les logs + +Ne jamais émettre en clair : + +- clé privée ou bytes secrets de keypair ; +- seed/seed phrase/mnemonic ; +- password/passphrase/PIN ; +- token API, bearer token, session token ou cookie d'authentification ; +- header `Authorization` complet ; +- clé de chiffrement ou secret de signature ; +- DSN/URL de connexion contenant des credentials ; +- contenu futur de `KS_SECRET_*` / `KB_SECRET_*` ou équivalent sensible ; +- tout objet `Debug` susceptible d'embarquer indirectement l'une de ces valeurs. + +Les adresses publiques, signatures publiques, Program IDs, slots et identifiants publics peuvent être loggés lorsqu'ils sont utiles. + +### Settings Logging + +`LoggingSettings` ne possède aucun champ de secret. Une future Config peut lui transmettre des chemins, niveaux, targets et paramètres de sortie, mais jamais les secrets de son propre document. + +### Responsabilité des callers + +La façade ne peut pas détecter de façon fiable qu'un arbitraire `Debug`/`Display` contient un secret. + +La règle est donc : + +- omission par défaut ; +- redaction explicite par le caller avant émission si la présence d'un champ est réellement nécessaire ; +- ne jamais logger un objet de configuration complet uniquement par commodité ; +- ne pas considérer le filtrage de niveau comme une protection de secret. + +### Helper de redaction + +Aucun helper générique de redaction n'est ajouté dans `0.1.2`. + +Un helper donnant une impression de protection automatique sans contrôler le contenu des objets serait trompeur. Une future nécessité concrète pourra introduire un type/helper explicitement borné. + +## Format, spans et compatibilité `log` + +### Format + +`0.1.2` stabilise un format humain exploitable, pas une sérialisation machine publique. + +Sont hors de la première surface : + +- JSON ; +- pretty/compact/human comme enum publique de formats ; +- choix arbitraire de formatter par le caller ; +- sérialisation Serde des événements. + +### Spans + +La crate est propriétaire de la stack tracing, mais `0.1.2` ne crée pas encore une façade publique KSP pour : + +- `span!` ; +- `#[instrument]` ; +- OpenTelemetry ; +- contexte distribué. + +Les cinq macros d'événements suffisent à la première fondation. Une surface spans sera ajoutée uniquement au premier besoin concret d'une crate async/runtime supérieure. + +### Compatibilité `log` + +La feature `tracing-log` de `tracing-subscriber` n'est pas activée maintenant. + +KSP ne possède encore aucune dépendance runtime supérieure démontrant un besoin de récupérer des événements provenant de la crate `log`. Cette compatibilité pourra être activée ultérieurement dans Logging si un transport/provider concret l'exige. + +## API publique candidate + +La façade crate-root visée à la fin de la release est : + +```text +ksp_logging_lib::error! +ksp_logging_lib::warn! +ksp_logging_lib::info! +ksp_logging_lib::debug! +ksp_logging_lib::trace! + +ksp_logging_lib::LogFilterLevel +ksp_logging_lib::TargetFilter +ksp_logging_lib::ConsoleOutput +ksp_logging_lib::ConsoleSettings +ksp_logging_lib::FileRotation +ksp_logging_lib::FileSettings +ksp_logging_lib::LoggingSettings +ksp_logging_lib::LoggingGuard +ksp_logging_lib::initialize + +ksp_logging_lib:: +``` + +Les modules d'implémentation restent privés. Les types externes `tracing*` ne deviennent pas le contrat public KSP. + +Arborescence candidate : + +```text +crates/ksp-logging-lib/ +├── Cargo.toml +├── README.md +├── TODO.md +├── USAGE.md +├── src/ +│ ├── lib.rs +│ ├── error.rs +│ ├── macros.rs +│ ├── settings.rs +│ └── runtime.rs +├── unit_tests/ +│ ├── settings.rs +│ └── runtime.rs +└── tests/ + ├── callsite.rs + └── public_api.rs +``` + +Cette arborescence reste ajustable si une séparation plus petite suffit. Aucun `mod.rs`, `pub mod`, `pub(super)` ou `pub(in ...)` n'est introduit. + +## Tests prévus + +### Façade/macros + +- les cinq macros sont accessibles depuis crate-root ; +- message simple ; +- champs structurés ; +- target explicite ; +- callsite file/module/line réel ; +- target implicite du caller ; +- absence de dépendance directe `tracing` dans une crate consommatrice de test si un fixture workspace est nécessaire. + +### Settings + +- constructeurs/getters ; +- niveaux `Off/Error/Warn/Info/Debug/Trace` ; +- target filters ; +- console stdout/stderr ; +- fichier Never/Hourly/Daily ; +- validation sans sortie ; +- validation des chaînes vides retenues. + +### Filtering + +- niveau default ; +- override de target exact ; +- override par préfixe ; +- target explicitement Off ; +- priorité d'un préfixe plus spécifique selon la sémantique `Targets` retenue. + +### Runtime + +- initialisation valide ; +- réinitialisation refusée ; +- subscriber déjà occupé ; +- console reçoit les événements attendus ; +- file output écrit les événements attendus ; +- rotation choisie est transmise au backend ; +- erreurs d'initialisation fichier remontent sous `ksp_core_lib::Error` avec code Logging ; +- guard conservé jusqu'au flush final. + +### Secrets + +Aucun test ne peut prouver qu'un caller futur ne loggera jamais un secret arbitraire. + +Les validations testables portent sur : + +- l'absence de champs sensibles dans `LoggingSettings` ; +- l'absence de dump automatique des settings/configurations ; +- les exemples/docs qui utilisent uniquement des valeurs publiques ; +- l'absence de helper présenté comme redaction automatique universelle. + +## Audits de dépendances + +À chaque tranche ajoutant une dépendance : + +```bash +cargo tree -p ksp-logging-lib +cargo tree -p ksp-logging-lib -d +cargo tree -p ksp-logging-lib -e features +``` + +Contrôles particuliers : + +- pas de `tracing-attributes` tant que `attributes` n'est pas nécessaire ; +- pas de `nu-ansi-term` par activation KSP de `ansi` ; +- pas de `tracing-log` par default feature ; +- pas de stack `env-filter`/regex ; +- pas de stack JSON/Serde ; +- pas de dépendance Config ; +- aucune seconde version évitable de la stack tracing ; +- `tracing-appender` peut tirer `time` pour son fonctionnement propre sans justifier d'activer la feature `time` de `tracing-subscriber`. + +## Référence historique bot3 + +L'archive bot3 fournie contient un ancien `ks-logging` plus large. + +Éléments utiles comme expérience historique : + +- possession des `WorkerGuard` par un objet `LoggingGuard` ; +- composition console + fichier ; +- filtering par routes/targets ; +- rotation file ; +- importance d'un lifecycle explicite pour le non-blocking. + +Éléments explicitement non migrés tels quels : + +- dépendance directe Logging -> Config ; +- parsing/validation de document Logging dans la crate ; +- JSON schema ; +- Serde/Serde JSON uniquement pour la configuration ; +- formats/routes multiples non requis ; +- surface de configuration historique plus large que le besoin KSP `0.1.2`. + +Cette archive reste une référence historique et non une source normative KSP. + +## Prereleases prévues + +### `0.1.2-pre.001` — audit + brainstorming + plan + +Objectifs : + +- auditer la base `0.1.1` ; +- auditer la stack tracing actuelle ; +- fixer ownership, macros/callsites, settings, filtering, console, fichier, lifecycle, erreurs et secrets ; +- dimensionner la suite ; +- ne pas créer encore la crate fonctionnelle ni ajouter de dépendance inutilisée. + +### `0.1.2-pre.002` — crate + settings + façade d'émission + +Objectifs : + +- créer `crates/ksp-logging-lib` et l'ajouter au workspace ; +- dépendre de `ksp-core-lib` ; +- revérifier puis ajouter `tracing` au workspace ; +- implémenter les types de settings indépendants de Config ; +- implémenter les cinq macros KSP ; +- ajouter les premiers tests publics de façade ; +- établir le test de callsite, en ajoutant `tracing-subscriber` à cette tranche seulement si le test l'utilise réellement ; sinon le fixer au début de `pre.003` avant de considérer les macros stabilisées. + +### `0.1.2-pre.003` — subscriber + console + filtering + +Objectifs : + +- revérifier puis ajouter `tracing-subscriber` si ce n'est pas déjà fait ; +- implémenter le mapping `LogFilterLevel` ; +- implémenter `Targets` default + overrides ; +- implémenter la couche console ; +- installer le subscriber global avec API fallible ; +- stabiliser le comportement de réinitialisation ; +- achever les tests de callsite avant toute poursuite vers le fichier. + +### `0.1.2-pre.004` — fichier + non-blocking + lifecycle + +Objectifs : + +- revérifier puis ajouter `tracing-appender` ; +- implémenter `FileSettings` et Never/Hourly/Daily ; +- utiliser le builder fallible du file appender ; +- utiliser le non-blocking en mode non-lossy ; +- introduire/achever `LoggingGuard` ; +- tester flush/lifetime et erreurs de fichier ; +- vérifier le graphe/features après unification de la stack complète. + +### `0.1.2-pre.005` — intégration + tests + audits + +Objectifs : + +- compléter les tests settings/filtering/runtime/façade ; +- vérifier la politique secrets dans docs/exemples ; +- auditer les réexports crate-root ; +- auditer la documentation de crate (`README.md`, `TODO.md`, `USAGE.md`) ; +- exécuter les audits Cargo/features/doublons et scripts réellement présents ; +- corriger les écarts sans ouvrir Config. + +### `0.1.2-pre.006` — validation finale + docs + cleanup + prompt 0.1.3 + +Objectifs : + +- exécuter les validations workspace finales ; +- fermer les écarts résiduels ; +- consolider la documentation durable ; +- synchroniser roadmap/index/changelog général s'il existe alors ; +- nettoyer/archive uniquement ce que les règles demandent ; +- préparer le prompt final `0.1.3 — ksp-config-lib` ; +- préparer la livraison finale avant `rel.001` et tag stable. + +Le découpage reste souple. Une tranche trop large est scindée ; une tranche devenue inutile est supprimée par correction explicite du plan. + +## Hors scope confirmé + +- `ksp-config-lib` et documents/profils Config ; +- parsing JSON/TOML de configuration ; +- Tauri ; +- wallet/keypair/signer ; +- RPC/WS/providers ; +- Program decoding/execution ; +- Store/PostgreSQL ; +- materializers ; +- workers/jobs/pipelines ; +- scenarios ; +- trading/ML ; +- OpenTelemetry/export réseau ; +- observabilité distribuée ; +- public span API/`#[instrument]` ; +- hot reload dynamique des filtres ; +- JSON log format ; +- field-based/domain filtering ; +- rotation par taille/compression ; +- multi-route avancé ; +- politique de rétention complexe ; +- compatibilité `log` tant qu'aucun besoin concret ne l'impose. + +## Critères de sortie de `0.1.2` + +La release peut être stabilisée lorsque : + +- `ksp-logging-lib` est la façade runtime unique KSP ; +- les cinq macros KSP fonctionnent sans dépendance `tracing` directe chez les consumers ; +- les tests prouvent le callsite réel ; +- les settings sont indépendants de Config ; +- le filtering default/target est déterministe ; +- console et fichier optionnel sont validés ; +- le file writer non bloquant est non-lossy et son guard est possédé explicitement ; +- la répétition d'initialisation retourne une erreur KSP au lieu de paniquer ; +- les erreurs utilisent Core sans dépendance inverse ; +- aucune fuite automatique de secret n'est introduite par la façade/settings ; +- le graphe/features respecte le besoin minimal retenu ; +- les validations workspace et audits présents sont propres ; +- la documentation finale et le prompt `0.1.3` sont prêts. + +## Questions ouvertes après `pre.001` + +Aucune question architecturale bloquante ne justifie du développement supplémentaire dans `pre.001`. + +Restent volontairement à confirmer par implémentation/tests : + +1. le mécanisme Rust exact des macros KSP (wrapper transparent ou réexport) qui préserve le callsite avec la plus petite surface ; +2. le détail visuel exact du formatter humain, sans transformer sa ponctuation en contrat public ; +3. l'utilité future d'une rétention bornée, d'ANSI, JSON, `tracing-log`, `EnvFilter`, spans ou reload, tous explicitement hors de la première surface tant qu'un besoin concret n'apparaît pas. + +La prochaine action après validation de ce plan est `0.1.2-pre.002`, pas l'ouverture de Config.