# Delta 0.1.3-pre.005 ## Base requise Livraison précédente validée : ```text 0.1.3-pre.004 ``` Version technique de cette base : ```text workspace.package.version = "0.1.3-pre.4" Cargo.toml header version = 44 ``` Validations utilisateur de `pre.004` exécutées le 2026-08-15 : ```text cargo fmt --all OK cargo check --workspace OK cargo clippy --workspace --all-targets OK cargo test --workspace OK cargo tree -p ksp-logging-lib OK cargo tree -p ksp-logging-lib -d OK — aucune duplication cargo tree -p ksp-logging-lib -e features OK ``` ## Objet de pre.005 Cette tranche active le runtime multi-sink derrière les contrats publics stabilisés en `pre.004`, mais reste bornée aux dimensions de routing directement portées par les métadonnées des events/spans : ```text level target ``` Le routing par champ structuré `domain` est scindé en `pre.006` plutôt que d'être approximé ou assimilé au target. ## Multi-sink runtime `RuntimeOutputs` possède maintenant : ```text console: Option files: Vec ``` Tous les `FileSettings` actifs sont préparés et installés simultanément. Chaque fichier conserve : ```text output_id WorkerGuard ErrorCounter ``` Le lifecycle de hot reload reste celui stabilisé en `0.1.2` : 1. validation et préparation complète des nouvelles sorties ; 2. swap du groupe de layers via le handle reload existant ; 3. conservation des compteurs des sorties retirées ; 4. destruction des anciens layers ; 5. destruction des anciens guards/writers. Un échec de préparation avant le swap laisse la configuration active intacte. ## Routing par output : level + target Chaque formatter utilise désormais un `RouteMakeWriter` interne. Lors de `make_writer_for(metadata)` : - `OutputFilter.level` décide si le niveau est accepté ; - `OutputFilter.targets[]` accepte le wildcard `*` ou un préfixe de target KSP ; - un writer désactivé absorbe la sortie sans écrire dans le sink concerné. Le takeover global existant reste distinct : ```text default_filter + TargetFilter[] ↓ groupe de sinks ↓ OutputFilter level/target propre à chaque sink ``` Le routing par output ne transforme pas les layers en `Filtered` reloadables. La composition `Targets.and_then(output_layers)` stabilisée pendant `0.1.2` est conservée. ## Scission du routing `domain` `domain` est un champ structuré déclaré par les callers, par exemple : ```rust ksp_logging_lib::info!( target: "ksp-config-lib", domain = "config", "configuration event" ); ``` Il n'est pas une propriété des métadonnées de target. Pour respecter le budget de tranche et éviter une sémantique incorrecte, `pre.005` refuse explicitement un output **actif** dont : ```text domains != ["*"] ``` Le refus utilise `logging.invalid_settings` avec le contexte : ```text runtime_contract = metadata-routing-before-domain-routing ``` Les contrats publics de `pre.004` restent inchangés : un output désactivé peut déjà porter son futur filtre domain et `LoggingSettings::validate()` continue de le valider structurellement. `pre.006` est insérée pour traiter : - domain porté directement par un event ; - domain d'un span ; - héritage vers les events sans champ direct ; - spans imbriqués ; - lifecycle `SpanEvents` ; - interaction avec les quatre formats et plusieurs sinks. ## Formats runtime Les quatre formats publics sont maintenant actifs : ```text Human Compact Pretty Json ``` Le manifest racine active pour `tracing-subscriber` : ```toml features = ["fmt", "json", "ansi"] ``` Aucune nouvelle dépendance directe n'est ajoutée au workspace. ## ANSI La console applique désormais réellement `ConsoleSettings::ansi()` pour les formats humains. Les fichiers restent construits derrière `StripAnsiWriter` et persistent sans ANSI. La combinaison : ```text console.format = Json console.ansi = true ``` est refusée par `LoggingSettings::validate()` afin de ne pas accepter une option qui serait sans effet. ## Compteurs par output fichier La vue agrégée existante reste disponible : ```rust LoggingGuard::dropped_lines() -> DroppedLines ``` avec : ```text console file total ``` `pre.005` ajoute : ```rust LoggingGuard::dropped_file_lines(output_id: &str) -> Option ``` Le compteur est cumulatif à travers les reloads pour un même `LoggingGuard` et un même `output_id`, y compris après retrait du sink. Un `output_id` qui n'a jamais été actif retourne `None`. ## Tests Les tests unitaires couvrent notamment : - préparation de plusieurs fichiers simultanés ; - console ANSI + format Compact ; - fichiers Pretty et Json ; - refus explicite d'un domain spécifique ; - mapping des niveaux de routing ; - writer désactivé ; - rejet JSON + ANSI console ; - conservation des tests de takeover, rotation, saturation et span lifecycle. Le test global runtime est étendu pour vérifier en un seul subscriber global : - échec transactionnel d'une configuration domain non encore supportée ; - quatre fichiers simultanés ; - formats Human, Compact, Pretty et Json ; - routing indépendant par target et niveau ; - silence des targets externes ; - stripping ANSI fichier ; - counters par `output_id` après retrait des sinks ; - hot reload concurrent existant ; - impossibilité d'une seconde initialisation globale. ## Plan de release regranularisé La scission explicite décale le reste du cycle : ```text pre.005 Logging : runtime multi-sink + level/target/formats pre.006 Logging : routing structuré domain pre.007 JSON/JSON Schema + std.logging.json pre.008 globals + profils + default_profile pre.009 compositions génériques par file_id pre.010 .env + process env + resolver ${...} pre.011 sensibilité + real/safe/provenance pre.012 adapter Config -> Logging pre.013 management + persistence JSON/.env pre.014 ownership audits + robustesse pre.015 clôture ``` Le schema `std.logging.schema.json` n'est donc pas figé avant validation du routing domain. ## Version technique La prerelease devient : ```text workspace.package.version = "0.1.3-pre.5" ``` Le manifest racine devient : ```text # version: 45 ``` ## Fichier ajouté ```text deltas/0.1.3/pre.005.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-logging-lib/README.md crates/ksp-logging-lib/TODO.md crates/ksp-logging-lib/USAGE.md crates/ksp-logging-lib/src/lib.rs crates/ksp-logging-lib/src/runtime.rs crates/ksp-logging-lib/src/settings.rs crates/ksp-logging-lib/src/writer.rs crates/ksp-logging-lib/tests/public_api.rs crates/ksp-logging-lib/tests/runtime.rs crates/ksp-logging-lib/unit_tests/runtime.rs crates/ksp-logging-lib/unit_tests/settings.rs crates/ksp-logging-lib/unit_tests/writer.rs docs/plans/000-README.md docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md ``` ## Hors scope confirmé Cette tranche n'implémente pas : - le routing runtime par champ structuré `domain` ; - JSON Config ou JSON Schema ; - `std.logging.json` ; - profils/composites Config ; - `.env` ou interpolation ; - secrets/redaction Config ; - modification de `ksp-config-lib` ; - rotation par taille/rétention/compression. ## Validations à exécuter par l'utilisateur ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test --workspace cargo tree -p ksp-logging-lib cargo tree -p ksp-logging-lib -d cargo tree -p ksp-logging-lib -e features ``` Les commandes Cargo ne sont pas déclarées réussies dans ce delta tant qu'elles n'ont pas été exécutées sur l'environnement utilisateur. ## Suite Après validation de cette tranche : ```text 0.1.3-pre.006 — ksp-logging-lib : routing structuré domain ``` Cette tranche devra fermer la dernière dimension du contrat `OutputFilter` avant l'introduction de `std.logging.schema.json`.