v0.1.2-pre.006

This commit is contained in:
2026-08-14 20:29:48 +02:00
parent d96f41fb8e
commit 8a0c119878
10 changed files with 745 additions and 35 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml # file: Cargo.toml
# version: 37 # version: 38
[workspace] [workspace]
resolver = "3" resolver = "3"
members = ["crates/ksp-core-lib", "crates/ksp-logging-lib"] members = ["crates/ksp-core-lib", "crates/ksp-logging-lib"]
[workspace.package] [workspace.package]
version = "0.1.2-pre.5.fix.1" version = "0.1.2-pre.6"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
@@ -18,6 +18,7 @@ solana-pubkey = { version = "^4.3", default-features = false }
tracing = { version = "^0.1", default-features = false, features = ["std"] } tracing = { version = "^0.1", default-features = false, features = ["std"] }
tracing-subscriber = { version = "^0.3", default-features = false, features = ["fmt"] } tracing-subscriber = { version = "^0.3", default-features = false, features = ["fmt"] }
tracing-appender = { version = "^0.2", default-features = false } tracing-appender = { version = "^0.2", default-features = false }
tokio = { version = "^1.53", default-features = false, features = ["rt", "rt-multi-thread", "macros"] }
[workspace.lints.rust] [workspace.lints.rust]
missing_docs = "warn" missing_docs = "warn"

View File

@@ -1,5 +1,5 @@
# file: crates/ksp-logging-lib/Cargo.toml # file: crates/ksp-logging-lib/Cargo.toml
# version: 3 # version: 4
[package] [package]
name = "ksp-logging-lib" name = "ksp-logging-lib"
@@ -13,5 +13,8 @@ tracing.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true
tracing-appender.workspace = true tracing-appender.workspace = true
[dev-dependencies]
tokio.workspace = true
[lints] [lints]
workspace = true workspace = true

View File

@@ -1,5 +1,5 @@
<!-- file: crates/ksp-logging-lib/README.md --> <!-- file: crates/ksp-logging-lib/README.md -->
<!-- version: 1 --> <!-- version: 2 -->
# ksp-logging-lib # ksp-logging-lib
@@ -19,6 +19,8 @@ La crate possède :
- les `WorkerGuard`, compteurs de lignes abandonnées, rotation fichier et stripping ANSI ; - les `WorkerGuard`, compteurs de lignes abandonnées, rotation fichier et stripping ANSI ;
- l'instrumentation de scopes synchrones et de `Future` async. - l'instrumentation de scopes synchrones et de `Future` async.
L'API async de production reste indépendante de tout executor. Tokio est utilisé uniquement comme `dev-dependency` afin de valider `instrument(...)` sur un executor réel en mode current-thread et multi-thread ; il ne fait pas partie des dépendances runtime de la crate.
## Frontières ## Frontières
Une crate KSP comportementale qui journalise son activité dépend de `ksp-logging-lib` et n'utilise pas directement `tracing`, `tracing-subscriber` ou `tracing-appender`. Une crate KSP comportementale qui journalise son activité dépend de `ksp-logging-lib` et n'utilise pas directement `tracing`, `tracing-subscriber` ou `tracing-appender`.

View File

@@ -1,14 +1,14 @@
<!-- file: crates/ksp-logging-lib/TODO.md --> <!-- file: crates/ksp-logging-lib/TODO.md -->
<!-- version: 1 --> <!-- version: 2 -->
# TODO ksp-logging-lib # TODO ksp-logging-lib
## À fermer avant la stable 0.1.2 ## À fermer avant la stable 0.1.2
- exécuter les validations Cargo complètes de `pre.005` puis de la tranche finale ; - exécuter les validations Cargo complètes de `pre.006`, y compris les tests Tokio current-thread/multi-thread ;
- exécuter explicitement le probe d'overhead ignoré et conserver son résultat dans le delta de validation approprié ; - vérifier que `cargo tree -p ksp-logging-lib -e normal` ne contient pas Tokio et que Tokio apparaît uniquement dans le graphe dev attendu ;
- vérifier une dernière fois le graphe de dépendances/features et l'absence de contournement de la façade KSP ; - refaire l'audit final du graphe/features et de l'ownership de la stack tracing ;
- synchroniser la documentation finale et le prompt `0.1.3 — ksp-config-lib`. - après validation de la prerelease finale, préparer `rel.001`, publier `workspace.package.version = "0.1.2"` et taguer `v0.1.2` conformément aux règles de release.
## Capacités différées ## Capacités différées

View File

@@ -1,5 +1,5 @@
<!-- file: crates/ksp-logging-lib/USAGE.md --> <!-- file: crates/ksp-logging-lib/USAGE.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Utilisation de ksp-logging-lib # Utilisation de ksp-logging-lib
@@ -116,3 +116,15 @@ ksp_logging_lib::warn!(
"logging queues dropped lines" "logging queues dropped lines"
); );
``` ```
## Instrumentation async et executor
`instrument(span, future)` accepte une `Future` standard et ne dépend d'aucun executor particulier :
```rust
let span = ksp_logging_lib::trace_span!(target: LOGGING_TARGET, "load_transactions");
let result = ksp_logging_lib::instrument(span, async_operation()).await;
```
La crate ne requiert pas Tokio en production. Tokio n'est présent qu'en `dev-dependency` pour valider la surface sur un executor réel, y compris après plusieurs suspensions et sur un runtime multi-thread. Un consumer peut donc utiliser l'executor adapté à son propre contexte sans que Logging lui en impose un.

View File

@@ -0,0 +1,118 @@
// file: crates/ksp-logging-lib/tests/tokio_span.rs
// version: 1
//! Integration tests for KSP span instrumentation on a real Tokio executor.
const TEST_TARGET: &str = "ksp-logging-lib";
#[derive(Clone)]
struct CountingSubscriber {
enters: std::sync::Arc<std::sync::atomic::AtomicU64>,
exits: std::sync::Arc<std::sync::atomic::AtomicU64>,
next_id: std::sync::Arc<std::sync::atomic::AtomicU64>,
}
impl CountingSubscriber {
fn new(enters: std::sync::Arc<std::sync::atomic::AtomicU64>, exits: std::sync::Arc<std::sync::atomic::AtomicU64>) -> Self {
return Self { enters, exits, next_id: std::sync::Arc::new(std::sync::atomic::AtomicU64::new(1)) };
}
}
impl tracing::Subscriber for CountingSubscriber {
fn enabled(&self, _metadata: &tracing::Metadata<'_>) -> bool {
return true;
}
fn new_span(&self, _span: &tracing::span::Attributes<'_>) -> tracing::span::Id {
let id = self.next_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
return tracing::span::Id::from_u64(id);
}
fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {
return;
}
fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {
return;
}
fn event(&self, _event: &tracing::Event<'_>) {
return;
}
fn enter(&self, _span: &tracing::span::Id) {
self.enters.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
return;
}
fn exit(&self, _span: &tracing::span::Id) {
self.exits.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
return;
}
}
fn test_span(enters: std::sync::Arc<std::sync::atomic::AtomicU64>, exits: std::sync::Arc<std::sync::atomic::AtomicU64>) -> ksp_logging_lib::Span {
let subscriber = CountingSubscriber::new(enters, exits);
return tracing::subscriber::with_default(subscriber, || -> ksp_logging_lib::Span {
return ksp_logging_lib::trace_span!(target: TEST_TARGET, "tokio_runtime_span", domain = "logging", executor = "tokio");
});
}
#[tokio::test(flavor = "current_thread")]
async fn instrumented_span_reenters_across_real_tokio_suspensions() {
let enters = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
let exits = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
let span = test_span(std::sync::Arc::clone(&enters), std::sync::Arc::clone(&exits));
let observed_enters = std::sync::Arc::clone(&enters);
let future = ksp_logging_lib::instrument(span, async move {
assert!(observed_enters.load(std::sync::atomic::Ordering::Relaxed) >= 1);
tokio::task::yield_now().await;
assert!(observed_enters.load(std::sync::atomic::Ordering::Relaxed) >= 2);
tokio::task::yield_now().await;
assert!(observed_enters.load(std::sync::atomic::Ordering::Relaxed) >= 3);
return 42_u32;
});
let value = future.await;
assert_eq!(value, 42_u32);
let enter_count = enters.load(std::sync::atomic::Ordering::Relaxed);
let exit_count = exits.load(std::sync::atomic::Ordering::Relaxed);
assert!(enter_count >= 3);
assert_eq!(enter_count, exit_count);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn instrumented_spans_are_usable_on_tokio_multithread_runtime() {
let enters = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
let exits = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
let first_span = test_span(std::sync::Arc::clone(&enters), std::sync::Arc::clone(&exits));
let second_span = test_span(std::sync::Arc::clone(&enters), std::sync::Arc::clone(&exits));
let first_task = tokio::spawn(ksp_logging_lib::instrument(first_span, async {
for _iteration in 0..32 {
tokio::task::yield_now().await;
}
return 20_u32;
}));
let second_task = tokio::spawn(ksp_logging_lib::instrument(second_span, async {
for _iteration in 0..32 {
tokio::task::yield_now().await;
}
return 22_u32;
}));
let first_result = first_task.await;
assert!(first_result.is_ok(), "first Tokio task must complete successfully");
let first_value = match first_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let second_result = second_task.await;
assert!(second_result.is_ok(), "second Tokio task must complete successfully");
let second_value = match second_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(first_value + second_value, 42_u32);
let enter_count = enters.load(std::sync::atomic::Ordering::Relaxed);
let exit_count = exits.load(std::sync::atomic::Ordering::Relaxed);
assert!(enter_count >= 4);
assert_eq!(enter_count, exit_count);
}

213
deltas/0.1.2/pre.006.md Normal file
View File

@@ -0,0 +1,213 @@
<!-- file: deltas/0.1.2/pre.006.md -->
<!-- version: 1 -->
# Delta 0.1.2-pre.006
## Base requise
Livraison précédente validée :
```text
0.1.2-pre.005-fix.001
```
La base porte :
```text
workspace.package.version = "0.1.2-pre.5.fix.1"
Cargo.toml header version = 37
```
## Validation de la base
La validation utilisateur de `pre.005-fix.001` est propre :
```text
cargo fmt --all OK
cargo check --workspace OK
cargo clippy --workspace --all-targets OK
cargo test --workspace OK
cargo test -p ksp-logging-lib --test overhead -- --ignored --nocapture OK
```
Le stress test concurrent ne produit plus le flux TRACE parasite corrigé par `pre.005-fix.001`.
Le probe diagnostic d'overhead a passé son garde-fou sur 200000 itérations :
```text
baseline = 19.658553 ms
reload = 28.807958 ms
```
Ces nombres restent des observations diagnostiques et non un benchmark contractuel.
## Objet de pre.006
`pre.006` est la prerelease finale prévue de `0.1.2`.
Elle :
- ajoute une validation des spans async sur un executor Tokio réel ;
- garde Tokio hors des dépendances runtime de `ksp-logging-lib` ;
- consolide la documentation de la crate ;
- ferme les TODO de prerelease ;
- prépare le prompt final de `0.1.3 — ksp-config-lib` ;
- prépare les validations finales précédant `rel.001`.
## Tokio uniquement pour les tests
Version actuelle vérifiée le 2026-08-14 :
```text
tokio 1.53.1
```
Le workspace centralise une contrainte de génération :
```toml
tokio = { version = "^1.53", default-features = false, features = ["rt", "rt-multi-thread", "macros"] }
```
`ksp-logging-lib` le consomme uniquement comme dev-dependency :
```toml
[dev-dependencies]
tokio.workspace = true
```
Aucun source de production de Logging n'importe Tokio. L'API `instrument(span, future)` reste fondée sur `std::future::Future` et reste indépendante de l'executor choisi par le consumer.
## Tests Tokio réels
Nouveau fichier :
```text
crates/ksp-logging-lib/tests/tokio_span.rs
```
### Current-thread
Le premier test utilise :
```text
#[tokio::test(flavor = "current_thread")]
```
Il instrumente une future contenant plusieurs `tokio::task::yield_now().await` et utilise un subscriber de test associé au span pour compter les `enter`/`exit`.
Le test exige plusieurs ré-entrées du span après suspension et un nombre final d'entrées/sorties identique.
### Multi-thread
Le second test utilise :
```text
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
```
Deux futures instrumentées sont lancées avec `tokio::spawn`, effectuent des suspensions répétées puis doivent terminer normalement. Le test vérifie également l'équilibre des `enter`/`exit`.
Ce test démontre l'utilisation correcte de la surface KSP sous un runtime Tokio multi-thread ; il ne prétend pas imposer ni mesurer une migration déterministe d'une même future entre worker threads.
## Documentation finale
Mises à jour :
- `crates/ksp-logging-lib/README.md` : indépendance de l'executor en production et statut test-only de Tokio ;
- `crates/ksp-logging-lib/USAGE.md` : exemple async et frontière executor ;
- `crates/ksp-logging-lib/TODO.md` : seules restent les validations finales et la future livraison stable ;
- `docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md` : statut validé de `pre.005-fix.001`, contenu `pre.006`, validations finales et absence de question architecturale bloquante ;
- `prompts/000-README.md` : ajout du prompt Config ;
- `prompts/003-V0_1_3_START_PROMPT.md` : prompt final pour ouvrir `0.1.3` après `v0.1.2`.
`ROADMAP.md` reste volontairement inchangé : `0.1.2` demeure en cours tant que `rel.001` et le tag `v0.1.2` ne sont pas validés.
Aucun changelog général n'existe actuellement dans le dépôt ; `pre.006` n'en crée pas artificiellement un.
## Version technique
La prerelease devient :
```text
workspace.package.version = "0.1.2-pre.6"
```
L'en-tête du manifest racine devient :
```text
# version: 38
```
Le manifest de `ksp-logging-lib` devient :
```text
# version: 4
```
## Fichiers du delta
```text
Cargo.toml
crates/ksp-logging-lib/Cargo.toml
crates/ksp-logging-lib/README.md
crates/ksp-logging-lib/TODO.md
crates/ksp-logging-lib/USAGE.md
crates/ksp-logging-lib/tests/tokio_span.rs
docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md
prompts/000-README.md
prompts/003-V0_1_3_START_PROMPT.md
deltas/0.1.2/pre.006.md
```
## Validations finales à exécuter
```bash
cargo fmt --all
cargo check --workspace
cargo build -p ksp-logging-lib
cargo clippy --workspace --all-targets
cargo test --workspace
cargo test -p ksp-logging-lib --test overhead -- --ignored --nocapture
cargo tree -p ksp-logging-lib
cargo tree -p ksp-logging-lib -d
cargo tree -p ksp-logging-lib -e features
cargo tree -p ksp-logging-lib -e normal
cargo tree -p ksp-logging-lib -e dev
```
Contrôles attendus en particulier :
- les deux tests de `tests/tokio_span.rs` passent ;
- `cargo build -p ksp-logging-lib` reste un build normal sans Tokio comme dépendance runtime ;
- le graphe `-e normal` n'inclut pas Tokio ;
- Tokio est visible uniquement via l'usage dev attendu ;
- aucune seconde version évitable n'apparaît ;
- l'audit ownership continue à interdire les contournements de la façade tracing.
Aucune validation Cargo n'est déclarée réussie dans ce delta avant exécution dans l'environnement de développement.
## Suite après validation
Si `pre.006` est propre, la prochaine livraison est :
```text
0.1.2-rel.001
```
Elle publiera :
```text
workspace.package.version = "0.1.2"
```
puis, après validation utilisateur, le commit final recevra :
```text
v0.1.2
```
La session fonctionnelle suivante pourra alors démarrer avec :
```text
prompts/003-V0_1_3_START_PROMPT.md
```

View File

@@ -1,11 +1,11 @@
<!-- file: docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md --> <!-- file: docs/plans/004-V0_1_2_LOGGING_FOUNDATION_PLAN.md -->
<!-- version: 13 --> <!-- version: 14 -->
# Plan KSP 0.1.2 — Logging foundation # Plan KSP 0.1.2 — Logging foundation
## Statut ## Statut
Plan actif de `0.1.2`, établi par `0.1.2-pre.001`, corrigé par `0.1.2-pre.001-fix.001`, concrétisé par la façade de `0.1.2-pre.002`, étendu au runtime subscriber par `0.1.2-pre.003`/`pre.003-fix.001`, puis complété et corrigé par `pre.004`/`pre.004-fix.001..004`. `pre.005` ouvre la phase d'intégration/robustesse : saturation déterministe, concurrence pendant hot reload, audit de takeover, validation des spans de timing, documentation de crate et probe d'overhead grossier. `pre.005-fix.001` corrige uniquement la pollution console du stress test concurrent : le runtime est désormais placé sur la configuration console silencieuse avant la libération des producteurs, puis les 32 reloads concurrents restent inchangés. Plan actif de `0.1.2`, établi par `0.1.2-pre.001`, corrigé par `0.1.2-pre.001-fix.001`, concrétisé par la façade de `0.1.2-pre.002`, étendu au runtime subscriber par `0.1.2-pre.003`/`pre.003-fix.001`, puis complété et corrigé par `pre.004`/`pre.004-fix.001..004`. `pre.005` a fermé la phase d'intégration/robustesse : saturation déterministe, concurrence pendant hot reload, audit de takeover, validation des spans de timing, documentation de crate et probe d'overhead grossier. `pre.005-fix.001` a supprimé la pollution console du stress test concurrent sans réduire la pression de reload. `pre.006` est la prerelease finale : elle ajoute une validation async sur executor Tokio réel uniquement en dev-dependency, consolide la documentation durable et prépare le prompt `0.1.3 — ksp-config-lib`.
`pre.003-fix.001` a été validé dans l'environnement de développement avec `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test --workspace` propres sur la version Cargo `0.1.2-pre.3.fix.1`. `pre.004` ajoute `tracing-appender`, remplace la console synchrone par un writer non bloquant, introduit le fichier `Never/Hourly/Daily`, possède les `WorkerGuard`, expose des compteurs cumulés de dropped lines, déporte le stripping ANSI côté worker fichier et conserve le hot reload transactionnel des sinks. `pre.004-fix.001` a rendu explicite le retrait des anciens layers avant leurs `WorkerGuard`, mais la validation utilisateur après `cargo clean` a reproduit exactement le même échec du marqueur fichier. Cette seconde validation a invalidé l'hypothèse selon laquelle ce défaut précis provenait du drain. La cause réelle est la sanitization ANSI native de `tracing-subscriber 0.3.23`, activée par défaut dans `fmt::Layer` : elle transforme les séquences de contrôle présentes dans les valeurs avant qu'elles n'atteignent le writer. `pre.004-fix.002` la conserve pour la console mais la désactive sur le formatter fichier afin que le `StripAnsiWriter` KSP, placé côté worker, reçoive les séquences ANSI originales et les supprime réellement. Le lifecycle explicite de `fix.001` est conservé car il reste correct pour le retrait des sinks non bloquants. La validation de `pre.004-fix.002` confirme ensuite que l'écriture fichier et le stripping ANSI fonctionnent, mais révèle que le target externe `sqlx` est encore persisté. La cause est la composition du filtre global comme enfant frère des formatters dans un `Vec<Layer>` : le `Vec` agrège l'intérêt de callsite en conservant l'intérêt le plus élevé de ses enfants, de sorte qu'un formatter intéressé peut masquer le `Interest::never()` du `Targets`. `pre.004-fix.003` compose donc `Targets` devant le `Vec` des sinks avec `Layer::and_then`; le filtre redevient global pour tout le groupe de sorties sans utiliser `with_filter`/`Filtered`. La validation de `pre.004-fix.003` confirme que tous les tests workspace passent, y compris le takeover externe et le fichier non bloquant, mais `cargo clippy --workspace --all-targets` signale encore `vec_init_then_push` dans la construction du composite reloadable. `pre.004-fix.004` applique uniquement cette correction de forme sans modifier le comportement runtime. La validation utilisateur finale de `pre.004-fix.004` sur `0.1.2-pre.4.fix.4` confirme `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test --workspace` propres ; le test runtime global passe avec takeover, fichier non bloquant, stripping ANSI et hot reload. Le graphe Cargo exécuté durant `pre.004` ne présentait aucun doublon et aucune activation KSP de `tracing-attributes`, `tracing-log`, `env-filter`, JSON/Serde ou ANSI formatter ; les dépendances n'ayant pas changé depuis, `pre.005` doit néanmoins refaire ces commandes avant validation de tranche. `pre.003-fix.001` a été validé dans l'environnement de développement avec `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test --workspace` propres sur la version Cargo `0.1.2-pre.3.fix.1`. `pre.004` ajoute `tracing-appender`, remplace la console synchrone par un writer non bloquant, introduit le fichier `Never/Hourly/Daily`, possède les `WorkerGuard`, expose des compteurs cumulés de dropped lines, déporte le stripping ANSI côté worker fichier et conserve le hot reload transactionnel des sinks. `pre.004-fix.001` a rendu explicite le retrait des anciens layers avant leurs `WorkerGuard`, mais la validation utilisateur après `cargo clean` a reproduit exactement le même échec du marqueur fichier. Cette seconde validation a invalidé l'hypothèse selon laquelle ce défaut précis provenait du drain. La cause réelle est la sanitization ANSI native de `tracing-subscriber 0.3.23`, activée par défaut dans `fmt::Layer` : elle transforme les séquences de contrôle présentes dans les valeurs avant qu'elles n'atteignent le writer. `pre.004-fix.002` la conserve pour la console mais la désactive sur le formatter fichier afin que le `StripAnsiWriter` KSP, placé côté worker, reçoive les séquences ANSI originales et les supprime réellement. Le lifecycle explicite de `fix.001` est conservé car il reste correct pour le retrait des sinks non bloquants. La validation de `pre.004-fix.002` confirme ensuite que l'écriture fichier et le stripping ANSI fonctionnent, mais révèle que le target externe `sqlx` est encore persisté. La cause est la composition du filtre global comme enfant frère des formatters dans un `Vec<Layer>` : le `Vec` agrège l'intérêt de callsite en conservant l'intérêt le plus élevé de ses enfants, de sorte qu'un formatter intéressé peut masquer le `Interest::never()` du `Targets`. `pre.004-fix.003` compose donc `Targets` devant le `Vec` des sinks avec `Layer::and_then`; le filtre redevient global pour tout le groupe de sorties sans utiliser `with_filter`/`Filtered`. La validation de `pre.004-fix.003` confirme que tous les tests workspace passent, y compris le takeover externe et le fichier non bloquant, mais `cargo clippy --workspace --all-targets` signale encore `vec_init_then_push` dans la construction du composite reloadable. `pre.004-fix.004` applique uniquement cette correction de forme sans modifier le comportement runtime. La validation utilisateur finale de `pre.004-fix.004` sur `0.1.2-pre.4.fix.4` confirme `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test --workspace` propres ; le test runtime global passe avec takeover, fichier non bloquant, stripping ANSI et hot reload. Le graphe Cargo exécuté durant `pre.004` ne présentait aucun doublon et aucune activation KSP de `tracing-attributes`, `tracing-log`, `env-filter`, JSON/Serde ou ANSI formatter ; les dépendances n'ayant pas changé depuis, `pre.005` doit néanmoins refaire ces commandes avant validation de tranche.
@@ -986,7 +986,7 @@ La saturation déterministe des queues, les reloads concurrents et l'audit compl
### `0.1.2-pre.005` — intégration + concurrence + tests + audits ### `0.1.2-pre.005` — intégration + concurrence + tests + audits
Statut : implémenté dans le delta `pre.005`, validations Cargo à exécuter. Statut : validé après `pre.005-fix.001`. Les validations utilisateur `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test --workspace` sont propres sur `0.1.2-pre.5.fix.1`. Le probe d'overhead ignoré a également été exécuté explicitement sur 200000 itérations et a passé son garde-fou grossier (`baseline=19.658553ms`, `reload=28.807958ms`).
Réalisé : Réalisé :
@@ -999,32 +999,41 @@ Réalisé :
- un test diagnostic ignoré compare un subscriber local fixe à la même couche placée derrière `reload::Layer`; il utilise un garde-fou volontairement très large contre une régression grossière et doit être exécuté explicitement avec `cargo test -p ksp-logging-lib --test overhead -- --ignored --nocapture` ; - un test diagnostic ignoré compare un subscriber local fixe à la même couche placée derrière `reload::Layer`; il utilise un garde-fou volontairement très large contre une régression grossière et doit être exécuté explicitement avec `cargo test -p ksp-logging-lib --test overhead -- --ignored --nocapture` ;
- aucun nouveau backend, setting public, format ou dépendance n'est introduit dans cette tranche. - aucun nouveau backend, setting public, format ou dépendance n'est introduit dans cette tranche.
Validations attendues avant clôture de `pre.005` : Les validations de `pre.005-fix.001` sont closes. Aucun répertoire `scripts/` n'était présent dans la base stable `0.1.1`; aucun audit script historique n'est donc déclaré exécuté par anticipation. Si un script existe dans le dépôt de développement au moment de la validation finale, il doit être exécuté selon les règles générales.
### `0.1.2-pre.006` — validation finale + docs + cleanup + prompt 0.1.3
Statut : implémenté dans le delta `pre.006`, validations Cargo finales à exécuter dans l'environnement de développement.
Réalisé :
- Tokio est centralisé dans `[workspace.dependencies]` sous `^1.53` avec uniquement `rt`, `rt-multi-thread` et `macros` ;
- `ksp-logging-lib` le consomme uniquement sous `[dev-dependencies]`, de sorte que son API/runtime de production reste executor-agnostic ;
- un test `#[tokio::test(flavor = "current_thread")]` instrumente une vraie future comportant plusieurs `yield_now().await` et vérifie plusieurs couples `enter/exit`, ce qui confirme la ré-entrée du span à chaque reprise réelle de polling ;
- un test `#[tokio::test(flavor = "multi_thread", worker_threads = 2)]` exécute deux futures instrumentées via `tokio::spawn`, avec suspensions répétées, et vérifie leur terminaison ainsi que l'équilibre `enter/exit` ;
- la documentation de crate précise que Tokio est un outil de test uniquement et n'est pas imposé aux consumers ;
- le TODO final est ramené aux validations `pre.006`, au contrôle du graphe normal/dev et à la future livraison `rel.001` ;
- le prompt `prompts/003-V0_1_3_START_PROMPT.md` est préparé pour ouvrir Config après la stable `v0.1.2`, avec relation Config -> `LoggingSettings`, profils/default_profile, env namespaces et politique secrets/public/debug ;
- l'index des prompts est synchronisé ;
- aucun changelog général n'existe actuellement dans le dépôt, donc aucun fichier de ce type n'est créé artificiellement en clôture.
Validations finales attendues :
```bash ```bash
cargo fmt --all cargo fmt --all
cargo check --workspace cargo check --workspace
cargo test --workspace cargo build -p ksp-logging-lib
cargo clippy --workspace --all-targets cargo clippy --workspace --all-targets
cargo test --workspace
cargo test -p ksp-logging-lib --test overhead -- --ignored --nocapture cargo test -p ksp-logging-lib --test overhead -- --ignored --nocapture
cargo tree -p ksp-logging-lib cargo tree -p ksp-logging-lib
cargo tree -p ksp-logging-lib -d cargo tree -p ksp-logging-lib -d
cargo tree -p ksp-logging-lib -e features cargo tree -p ksp-logging-lib -e features
cargo tree -p ksp-logging-lib -e normal
cargo tree -p ksp-logging-lib -e dev
``` ```
Aucun répertoire `scripts/` n'était présent dans la base stable `0.1.1`; aucun audit script historique n'est donc déclaré exécuté par anticipation. Si un script existe dans le dépôt de développement au moment de la validation, il doit être exécuté selon les règles générales. Le contrôle spécifique de cette tranche est que Tokio soit visible dans le graphe dev des tests mais absent du graphe normal de `ksp-logging-lib`.
### `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` en documentant la conversion Config -> `LoggingSettings` et le hot reload ;
- 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. Le découpage reste souple. Une tranche trop large est scindée ; une tranche devenue inutile est supprimée par correction explicite du plan.
@@ -1060,6 +1069,7 @@ La release peut être stabilisée lorsque :
- les crates comportementales de test utilisent exclusivement la façade KSP pour événements et spans ; - les crates comportementales de test utilisent exclusivement la façade KSP pour événements et spans ;
- les cinq macros événements fonctionnent avec target KSP explicite et callsite réel ; - les cinq macros événements fonctionnent avec target KSP explicite et callsite réel ;
- la surface de spans sync/async fonctionne sans exposer une dépendance `tracing` directe aux consumers ; - la surface de spans sync/async fonctionne sans exposer une dépendance `tracing` directe aux consumers ;
- l'instrumentation async est validée sur un executor réel current-thread et multi-thread sans ajouter d'executor aux dépendances runtime de Logging ;
- `NEW | CLOSE` permet d'obtenir rapidement début/fin et temps busy/idle lorsque demandé ; - `NEW | CLOSE` permet d'obtenir rapidement début/fin et temps busy/idle lorsque demandé ;
- les settings sont indépendants de Config ; - les settings sont indépendants de Config ;
- les targets externes sont silencieux par défaut et les détails utiles sont réémis explicitement par leur propriétaire KSP ; - les targets externes sont silencieux par défaut et les détails utiles sont réémis explicitement par leur propriétaire KSP ;
@@ -1075,7 +1085,7 @@ La release peut être stabilisée lorsque :
- les validations workspace et audits présents sont propres ; - les validations workspace et audits présents sont propres ;
- la documentation finale et le prompt `0.1.3` sont prêts. - la documentation finale et le prompt `0.1.3` sont prêts.
## Questions ouvertes après `pre.005` ## Questions ouvertes après `pre.006`
Les deux questions d'API propres à `pre.002` sont résolues : Les deux questions d'API propres à `pre.002` sont résolues :
@@ -1084,10 +1094,8 @@ Les deux questions d'API propres à `pre.002` sont résolues :
La composition de reload est désormais fixée pour cette release à un `Vec` de layers boxed derrière une `reload::Layer`, ce qui autorise l'activation/désactivation des sinks et le remplacement de leurs paramètres sans second subscriber global. Le takeover `Targets` est composé avec `Layer::and_then` devant le `Vec` des sinks afin que son `Interest::never()` gouverne réellement tout le groupe de sorties ; les layers de sortie reloadables ne sont pas des `Filtered` remplacés directement. Pour les changements de sinks, `pre.004-fix.001` utilise `Handle::modify` afin de récupérer le `Vec` retiré : les anciens layers sont détruits avant les `WorkerGuard` correspondants, ce qui fixe explicitement le lifecycle de drain des writers non bloquants. `pre.004-fix.002` distingue en outre la sanitization des valeurs : activée côté console, désactivée côté formatter fichier car le `StripAnsiWriter` KSP possède la responsabilité de suppression avant persistence. `pre.004-fix.003` ferme enfin la fuite des targets externes révélée par le test d'intégration fichier. La composition de reload est désormais fixée pour cette release à un `Vec` de layers boxed derrière une `reload::Layer`, ce qui autorise l'activation/désactivation des sinks et le remplacement de leurs paramètres sans second subscriber global. Le takeover `Targets` est composé avec `Layer::and_then` devant le `Vec` des sinks afin que son `Interest::never()` gouverne réellement tout le groupe de sorties ; les layers de sortie reloadables ne sont pas des `Filtered` remplacés directement. Pour les changements de sinks, `pre.004-fix.001` utilise `Handle::modify` afin de récupérer le `Vec` retiré : les anciens layers sont détruits avant les `WorkerGuard` correspondants, ce qui fixe explicitement le lifecycle de drain des writers non bloquants. `pre.004-fix.002` distingue en outre la sanitization des valeurs : activée côté console, désactivée côté formatter fichier car le `StripAnsiWriter` KSP possède la responsabilité de suppression avant persistence. `pre.004-fix.003` ferme enfin la fuite des targets externes révélée par le test d'intégration fichier.
`pre.005` ferme les deux points de robustesse restants de `pre.004` : la saturation est testée avec le builder de production et une queue bornée injectée uniquement dans le test ; la concurrence/reload est exercée par quatre producteurs pendant des reconfigurations répétées. Le probe d'overhead existe désormais comme test diagnostic explicitement ignoré par défaut. `pre.005` ferme les deux points de robustesse restants de `pre.004` : la saturation est testée avec le builder de production et une queue bornée injectée uniquement dans le test ; la concurrence/reload est exercée par quatre producteurs pendant des reconfigurations répétées. Le probe d'overhead existe désormais comme test diagnostic explicitement ignoré par défaut. `pre.006` complète cette couverture par deux tests Tokio réels sans faire de Tokio une dépendance runtime de Logging.
Reste à confirmer pendant la validation finale sans remettre en cause le contrat : Aucune question architecturale bloquante ne reste ouverte pour la stable `0.1.2`. Le détail visuel exact du formatter humain reste volontairement non contractuel : sa ponctuation peut évoluer ultérieurement tant que les informations et garanties publiques documentées sont préservées.
1. le détail visuel exact du formatter humain, sans transformer sa ponctuation en contrat public. La prochaine action après validation de `pre.006` est la livraison `0.1.2-rel.001`, le passage de `workspace.package.version` à `0.1.2`, les validations de publication puis le tag stable `v0.1.2`. La session fonctionnelle suivante est `0.1.3 — ksp-config-lib` avec le prompt `prompts/003-V0_1_3_START_PROMPT.md`.
La prochaine action après validation de `pre.005` est `0.1.2-pre.006` : validation finale, documentation/cleanup, synchronisation des points d'entrée et préparation du prompt `0.1.3 — ksp-config-lib`.

View File

@@ -1,5 +1,5 @@
<!-- file: prompts/000-README.md --> <!-- file: prompts/000-README.md -->
<!-- version: 4 --> <!-- version: 5 -->
# Prompts KSP # Prompts KSP
@@ -23,3 +23,4 @@ Le prompt générique `0.1.x` a été affiné pendant `0.0.3` puis remplacé par
- [`001-V0_1_1_START_PROMPT.md`](001-V0_1_1_START_PROMPT.md) — prompt historique ouvrant la première release fonctionnelle `0.1.1` après publication stable de `0.0.3` ; - [`001-V0_1_1_START_PROMPT.md`](001-V0_1_1_START_PROMPT.md) — prompt historique ouvrant la première release fonctionnelle `0.1.1` après publication stable de `0.0.3` ;
- [`002-V0_1_2_START_PROMPT.md`](002-V0_1_2_START_PROMPT.md) — prompt final destiné à ouvrir `0.1.2 — Logging foundation` après publication stable de `0.1.1`. - [`002-V0_1_2_START_PROMPT.md`](002-V0_1_2_START_PROMPT.md) — prompt final destiné à ouvrir `0.1.2 — Logging foundation` après publication stable de `0.1.1`.
- [`003-V0_1_3_START_PROMPT.md`](003-V0_1_3_START_PROMPT.md) — prompt final destiné à ouvrir `0.1.3 — Configuration foundation` après publication stable de `0.1.2`.

View File

@@ -0,0 +1,352 @@
<!-- file: prompts/003-V0_1_3_START_PROMPT.md -->
<!-- version: 1 -->
# Prompt de démarrage KSP 0.1.3
## 1. Contexte de reprise
Projet : `khadhroony-solana-project` (KSP).
Base requise avant ouverture de cette session :
```text
v0.1.2 stable
```
La release `0.1.2` a introduit `ksp-logging-lib` comme façade KSP unique de logging/tracing runtime. `0.1.3` ne doit pas rouvrir cette architecture ; Config doit consommer ses contrats publics.
Release à développer :
```text
0.1.3 — Configuration foundation
```
## 2. Mission
Introduire `ksp-config-lib` comme propriétaire des documents de configuration KSP, de leur résolution, de leurs profils, de leur validation et des modifications/persistences explicitement autorisées.
La première prerelease est obligatoirement une tranche de brainstorming, audit et planification. Ne pas commencer directement par une implémentation large de Config.
## 3. Base architecturale à préserver
Dépendances candidates de la nouvelle crate :
```text
ksp-config-lib
-> ksp-core-lib
-> ksp-logging-lib
```
Relations interdites :
```text
ksp-core-lib -X-> ksp-config-lib
ksp-logging-lib -X-> ksp-config-lib
```
`ksp-logging-lib` possède toujours ses propres `LoggingSettings` et son lifecycle `initialize` / `reinitialize`. Config lit/résout ses documents puis construit explicitement les settings publics Logging ; Logging ne lit aucun document Config et ne connaît aucun profil.
## 4. Première prerelease obligatoire : `0.1.3-pre.001`
Cette tranche doit produire un plan détaillé avant développement fonctionnel.
Elle doit notamment :
1. auditer l'état réel du workspace stable `0.1.2` ;
2. réauditer les règles Config déjà présentes dans le dépôt et les archives historiques pertinentes sans les copier aveuglément ;
3. inventorier les documents de configuration nécessaires à court terme ;
4. distinguer valeurs globales, valeurs profilées, sélection du profil et composition propre aux exécutables ;
5. fixer la politique de résolution document -> profil -> env override -> valeur effective ;
6. fixer la validation, les diagnostics et les erreurs Core nécessaires ;
7. fixer les opérations de modification/sauvegarde autorisées et leurs garanties d'atomicité ;
8. fixer la frontière secrets/public/debug ;
9. définir la relation exacte avec `LoggingSettings` et le hot reload Logging ;
10. décider si le périmètre Config tient proprement dans une seule release `0.1.3` ou doit être scindé ;
11. produire `docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md` et le plan souple des prereleases suivantes.
Le `pre.001` reste une tranche de planification : ne pas ajouter de dépendance fonctionnelle inutilisée et ne pas créer une large surface de code avant validation du plan.
## 5. Documents spécialisés
La configuration KSP doit être pensée comme plusieurs documents spécialisés plutôt qu'un unique fichier global monolithique lorsque les responsabilités sont distinctes.
Le point déjà fixé est notamment :
```text
logging.config.json
```
séparé de la configuration applicative générale.
Le `pre.001` doit inventorier les autres documents réellement nécessaires au premier cycle et éviter de créer prématurément des fichiers pour des composants non développés.
Les schemas doivent être placés sous :
```text
config/schemas/
```
et les exemples sous :
```text
config/
```
La structure exacte reste à valider dans le plan Config.
## 6. Valeurs globales et profils
Une valeur qui ne varie pas selon le profil reste hors profils.
Exemples historiques déjà retenus comme principe :
```text
logging.logs_directory
wallets_directory
```
Le `default_profile` est autonome : il sélectionne un profil par défaut mais ne doit pas être artificiellement imbriqué dans chacun des profils.
Les fichiers de composition propres à un binaire peuvent sélectionner les documents utilisés et remplacer les profils choisis lorsqu'un besoin concret l'exige.
## 7. Variables d'environnement
Toutes les variables d'environnement applicatives doivent être namespacées selon leur propriétaire fonctionnel.
Pour les composants génériques KSP / `ksp-*` :
```text
KS_*
KS_PUBLIC_*
KS_SECRET_*
```
Pour les futures applications/composants bot `kb-*` lorsqu'ils existent :
```text
KB_*
KB_PUBLIC_*
KB_SECRET_*
```
Le `pre.001` doit formaliser précisément la correspondance entre document, clé de configuration et override d'environnement.
Aucune variable sans préfixe propriétaire ne doit être introduite.
## 8. Secrets, public et debug
La résolution Config doit distinguer les valeurs exposables de celles qui ne doivent jamais traverser une frontière publique.
Politique déjà retenue :
- `KS_SECRET_*` / `KB_SECRET_*` : jamais exposés ;
- `KS_PUBLIC_*` / `KB_PUBLIC_*` : exposables ;
- autres valeurs : exposition autorisée uniquement dans le contexte debug prévu par les contrats applicatifs.
La surface Config ne doit pas transformer cette politique en simple convention documentaire : le plan doit préciser où elle est appliquée et testée.
Cela ne change pas la responsabilité de Logging concernant le contenu des messages : `ksp-logging-lib` ne scanne ni ne redacte automatiquement les secrets fournis par ses callers.
## 9. Relation Config -> Logging
Config peut produire un `ksp_logging_lib::LoggingSettings` à partir de sa configuration effective puis appeler le lifecycle Logging au niveau d'orchestration approprié.
Séquence conceptuelle :
```text
documents Config
-> résolution/profil/env
-> configuration Logging effective
-> LoggingSettings
-> ksp_logging_lib::initialize(...) ou reinitialize(...)
```
Le mécanisme qui détecte un changement de fichier, s'il est introduit plus tard, appartient à Config/application/orchestration ; Logging fournit uniquement sa reconfiguration runtime.
`0.1.3-pre.001` doit préciser qui possède le `LoggingGuard` dans les premières compositions concrètes sans créer de singleton global Config inutile.
## 10. Validation et erreurs
`ksp-config-lib` doit réutiliser :
```text
ksp_core_lib::Error
ksp_core_lib::ErrorCode
ksp_core_lib::ErrorContext
ksp_core_lib::Result<T>
```
Les codes propres à Config appartiennent au domaine Config et ne doivent pas être ajoutés comme connaissance métier à Core.
Les diagnostics doivent distinguer autant que nécessaire :
- document absent lorsque obligatoire ;
- syntaxe invalide ;
- schema/contrainte invalide ;
- profil demandé absent ;
- valeur effective invalide ;
- override d'environnement invalide ;
- opération de sauvegarde/modification impossible.
La nomenclature exacte des ErrorCode est décidée dans le plan puis ajoutée seulement quand chaque erreur devient nécessaire.
## 11. Mutation et persistence
La configuration n'est pas uniquement un lecteur statique : le périmètre candidat de `0.1.3` comprend les modifications/sauvegardes explicitement autorisées.
Le `pre.001` doit décider :
- quels documents peuvent être modifiés par API ;
- quelles valeurs sont read-only ;
- comment préserver format/version/schema ;
- comment éviter un fichier partiellement écrit ;
- comment représenter une modification rejetée ;
- comment distinguer configuration souhaitée et configuration effective lorsqu'un composant runtime ne peut pas appliquer immédiatement une valeur.
Si cette surface rend la release trop large, elle doit être scindée plutôt que comprimée artificiellement.
## 12. Frontière application/Tauri
`0.1.3` reste une release de bibliothèque Config.
La validation desktop complète est prévue ensuite, par défaut dans :
```text
0.1.4 — ksp-app-config-desk
```
Les DTO/bindings Tauri n'appartiennent donc pas automatiquement à `ksp-config-lib`. TS-RS reste principalement une frontière des applications Tauri et ne doit être dérivé dans une crate générique que pour un contrat externe réellement générique et indépendant de Tauri.
## 13. Règles Rust et Cargo à conserver
Conserver les règles normatives du dépôt, notamment :
- Rust 2024 ;
- `unsafe` interdit ;
- pas de `unwrap`, `expect`, `panic` dans le code production ;
- pas d'opérateur `?` ;
- retours explicites selon les règles Clippy du workspace ;
- imports de traits seulement lorsque nécessaire, chemins pleinement qualifiés sinon ;
- pas de `mod.rs` ;
- pas de `pub(super)` / `pub(in ...)` ;
- code et Rustdoc en anglais ;
- documentation Markdown en français ;
- tests unitaires hors `src` selon la convention du dépôt ;
- dépendances externes communes déclarées uniquement sous `[workspace.dependencies]` puis consommées avec `.workspace = true` ;
- versions externes sous contraintes caret de génération compatibles, après vérification de la version actuelle au moment de l'ajout ;
- ne pas versionner `Cargo.lock`.
## 14. Logging dans Config
`ksp-config-lib` contient du comportement runtime et doit normalement dépendre de `ksp-logging-lib` pour ses propres événements utiles.
Elle ne doit jamais importer directement :
```text
tracing
tracing-subscriber
tracing-appender
```
Ses targets KSP explicites utilisent le nom Cargo :
```text
ksp-config-lib
```
Les détails d'une bibliothèque tierce utilisés par Config sont silencieux par défaut ; Config réémet sous son propre target les informations réellement utiles au diagnostic KSP.
## 15. Hors scope initial
Sauf décision explicite du `pre.001`, ne pas ouvrir dans `0.1.3` :
- application desktop Config ;
- Tauri comme dépendance de `ksp-config-lib` ;
- Wallet ;
- Store/PostgreSQL ;
- RPC/WS/provider ;
- Program/decoder/execution ;
- workers/jobs/pipelines ;
- trading/ML ;
- watcher générique de tous les fichiers du projet ;
- service distribué de configuration ;
- secrets manager distant ;
- configuration spécifique à des composants qui n'existent pas encore.
## 16. Git, versions et deltas
Chaque livraison est un delta commité :
```text
pre.NNN
pre.NNN-fix.NNN
rel.NNN
```
Cargo utilise les identifiants SemVer sans zéros de tête :
```text
0.1.3-pre.1
0.1.3-pre.1.fix.1
```
Les noms de deltas/documents peuvent conserver la représentation `pre.001` / `fix.001`.
Une correction ultérieure ne réécrit pas un delta déjà livré.
Seul le commit final stable reçoit :
```text
v0.1.3
```
## 17. Première action de la session
Commencer par `0.1.3-pre.001` : audit, brainstorming et plan de travail.
Ne pas traiter ce `pre.001` comme un simple audit passif. Il doit produire les décisions nécessaires au développement des tranches suivantes et une matrice claire des responsabilités Config.
## 18. Dernière prerelease
La dernière prerelease de `0.1.3` devra :
- exécuter les validations finales ;
- consolider la documentation durable ;
- nettoyer/archiver uniquement ce que les règles exigent ;
- préparer le prompt de la release suivante ;
- vérifier le graphe de dépendances/features ;
- fermer les TODO de release ou les reporter explicitement ;
- préparer la livraison `rel.001` et le tag stable après validation utilisateur.
## 19. Validations minimales attendues
Lorsque les commandes sont applicables :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test --workspace
cargo tree -p ksp-config-lib
cargo tree -p ksp-config-lib -d
cargo tree -p ksp-config-lib -e features
```
Exécuter également tout script d'audit réellement présent dans le dépôt au moment de la validation.
Aucune commande non exécutée ne doit être déclarée réussie.
## 20. Critère de succès du `pre.001`
Le `pre.001` est terminé lorsque nous savons précisément :
- quels documents existent dans la première surface Config ;
- ce qui est global et ce qui est profilé ;
- comment fonctionne `default_profile` ;
- comment se résolvent les overrides `KS_*`/`KB_*` ;
- comment les secrets/public/debug sont classifiés ;
- quels contrats de lecture/résolution/validation/mutation sont publics ;
- comment Config construit `LoggingSettings` sans dépendance inverse ;
- quelles dépendances externes sont réellement nécessaires ;
- si `0.1.3` reste une seule release ou doit être scindée ;
- quel est le découpage des prereleases de développement.