# Delta 0.1.2-pre.004-fix.003 ## Base requise Livraison précédente : ```text 0.1.2-pre.004-fix.002 ``` La base porte : ```text workspace.package.version = "0.1.2-pre.4.fix.2" Cargo.toml header version = 33 ``` ## Validation remontée Après application de `pre.004-fix.002` : ```text cargo fmt --all OK cargo check --workspace OK cargo clippy --workspace --all-targets OK cargo test --workspace ECHEC ``` Le marqueur fichier précédemment absent est désormais correctement persisté et les assertions de présence du target, du callsite et d'absence d'ANSI passent. Le test runtime global échoue plus loin sur : ```text assertion failed: !file_text.contains("external marker must remain silent") ``` Le défaut restant concerne donc exclusivement le takeover : un événement `tracing` émis directement avec le target externe `sqlx` atteint encore le sink fichier alors que la politique KSP exige son silence total. ## Cause réelle `pre.003-fix.001` avait évité le panic `Filtered`/`FilterId` en plaçant `Targets` comme layer global distinct dans le même : ```text Vec>> ``` que les formatters. Cette composition n'est toutefois pas correcte pour le filtrage global au niveau des callsites. L'implémentation `Layer` de `Vec` agrège `register_callsite` en conservant l'intérêt le plus élevé retourné par ses enfants. Un `fmt::Layer` intéressé par le callsite peut donc produire un intérêt actif alors que `Targets` retourne `Interest::never()` pour un target externe. Lorsque le callsite est enregistré comme toujours actif, `enabled()` n'est ensuite pas consulté à chaque émission. Le `Targets` frère du formatter ne peut donc plus bloquer l'événement externe. Le test avec `sqlx` expose précisément cette fuite. ## Correction Les layers de sortie sont d'abord construits dans un `Vec` : ```text outputs ├── console fmt layer, si actif └── file fmt layer, si actif ``` Le takeover est ensuite composé **devant tout ce groupe** : ```text Targets .and_then(outputs) ``` et ce composite unique devient l'élément du `Vec` reloadable : ```text reload::Layer └── Vec └── Targets -> output layers ``` Cette forme rétablit la sémantique de filtre global : un `Interest::never()` produit par `Targets` court-circuite le groupe de sinks avant leur formatter. Elle conserve simultanément les propriétés requises : - aucun `Layer::with_filter` n'est utilisé sur un layer remplacé à chaud ; - aucun `Filtered` et donc aucun `FilterId` reloadable n'est introduit ; - console et fichier restent activables/désactivables dynamiquement ; - `Handle::modify` continue de récupérer l'ancien composite avant destruction de ses `WorkerGuard` ; - la sanitization console et le stripping ANSI fichier de `fix.002` restent inchangés ; - l'API publique reste inchangée. Le test d'intégration runtime conserve son assertion directe sur un événement `tracing::error!` de target `sqlx`. Il reste donc le test de non-régression du takeover effectif, au-delà du test unitaire de `Targets::would_enable`. ## Version technique Ce correctif modifie du Rust. La version workspace devient : ```text workspace.package.version = "0.1.2-pre.4.fix.3" ``` et l'en-tête du `Cargo.toml` racine devient : ```text # version: 34 ``` ## Fichiers du delta ```text Cargo.toml crates/ksp-logging-lib/src/runtime.rs crates/ksp-logging-lib/unit_tests/runtime.rs docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md deltas/0.1.2/pre.004-fix.003.md ``` ## Validations à exécuter ```bash cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test --workspace ``` Aucune dépendance n'est modifiée par ce fix. Après validation propre, la tranche suivante reste : ```text 0.1.2-pre.005 — intégration + concurrence + saturation + audits ```