From c9a0f7fd377ff666d277390df075ccb7ec87c1fe Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Tue, 18 Aug 2026 16:47:54 +0200 Subject: [PATCH] v0.2.3-pre.008 --- Cargo.toml | 4 +- .../tests/release_completeness.rs | 32 +++- deltas/0.2.3/pre.008.md | 117 +++++++++++++++ .../010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md | 12 +- docs/validation/000-README.md | 3 +- ...05-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md | 137 ++++++++++++++++++ 6 files changed, 300 insertions(+), 5 deletions(-) create mode 100644 deltas/0.2.3/pre.008.md create mode 100644 docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md diff --git a/Cargo.toml b/Cargo.toml index b5d8c80..38aefb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 128 +# version: 129 [workspace] resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib"] [workspace.package] -version = "0.2.3-pre.7" +version = "0.2.3-pre.8" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-onchain-transport-lib/tests/release_completeness.rs b/crates/ksp-onchain-transport-lib/tests/release_completeness.rs index c1a926c..3a2aaad 100644 --- a/crates/ksp-onchain-transport-lib/tests/release_completeness.rs +++ b/crates/ksp-onchain-transport-lib/tests/release_completeness.rs @@ -1,5 +1,5 @@ // file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs -// version: 12 +// version: 13 //! Release-level completeness canaries for the `0.2.1` HTTP foundation contract. @@ -400,3 +400,33 @@ fn release_pre_007_completes_all_v0_2_3_transaction_wrappers_with_exact_safety_c assert_eq!(simulations.len(), 1); assert_eq!(reads.len() + writes.len() + simulations.len(), 11); } + +#[test] +fn release_pre_008_ksp_transport_007_retro_audit_covers_all_typed_current_methods() { + let mut audited = std::vec::Vec::<&str>::new(); + for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { + if matches!( + descriptor.coverage_release(), + ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 + | ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 + | ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 + ) { + audited.push(descriptor.method()); + assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported); + match descriptor.operation_kind() { + ksp_onchain_transport_lib::RpcOperationKind::Read | ksp_onchain_transport_lib::RpcOperationKind::Simulation => { + assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); + }, + ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => { + assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch); + }, + } + } + } + audited.sort_unstable(); + assert_eq!(audited.len(), 37); + assert_eq!(audited.first(), std::option::Option::Some(&"getAccountInfo")); + assert_eq!(audited.last(), std::option::Option::Some(&"simulateTransaction")); + let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist"); + assert!(get_transaction.request_form_status().has_deprecated_legacy()); +} diff --git a/deltas/0.2.3/pre.008.md b/deltas/0.2.3/pre.008.md new file mode 100644 index 0000000..4cea06b --- /dev/null +++ b/deltas/0.2.3/pre.008.md @@ -0,0 +1,117 @@ + + + +# Delta `0.2.3-pre.008` — réaudit rétroactif `KSP-TRANSPORT-007` + +## Base requise + +```text +0.2.3-pre.007 +``` + +La base opérateur a été validée avec `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --workspace --all-targets` et `cargo test -p ksp-onchain-transport-lib` : 182 tests unitaires, 19 tests public API et 13 tests release completeness passent ; le smoke Devnet Transport reste opt-in/ignored. + +## Objectif + +Appliquer rétroactivement `KSP-TRANSPORT-007` à tous les wrappers HTTP typés courants livrés depuis `0.2.1`, avant la tranche de clôture finale : + +```text +4 Foundation +22 Accounts/Tokens/Cluster +11 Transactions +37 wrappers typés courants +``` + +L'audit doit détecter toute possibilité RPC supportée mais absente : paramètre, config, overload, forme legacy, contrainte déterministe ou information de réponse significative. + +## Audit effectué + +Le contrôle croise : + +- documentation HTTP Solana courante au 18 août 2026 ; +- Agave `v4.2.1` `rpc.rs` ; +- Agave `v4.2.1` `rpc-client-types/config.rs` ; +- Agave `v4.2.1` `rpc-client-types/response.rs` ; +- Agave `v4.2.1` `transaction-status-client-types/lib.rs` ; +- surfaces publiques et tests KSP existants. + +`v4.2.1` reste la génération runtime stable retenue : `v4.2` est recommandée pour adoption générale Mainnet-beta depuis le 10 août 2026 et ses activations Mainnet-beta ont commencé le 17 août 2026. Le `master` Agave est déjà en `4.3.0-alpha` et n'est pas pris comme contrat stable de cette release. + +## Verdict + +**Aucune remédiation fonctionnelle requise.** Les 37 wrappers couvrent déjà toute la surface sémantique supportée retenue par l'audit. + +Le réaudit confirme notamment les extensions KSP qui vont au-delà de certaines pages publiques mais correspondent au runtime Agave : `binary`, `sortResults`, `tokenAccountState`, `clientId`, `inflationRewardsCommissionBps`, `transactionIndex`, `recentBlockhash` et les champs riches de `simulateTransaction`. + +La forme bare encoding legacy de `getTransaction` reste distincte et deprecated. Les syntaxes strictement équivalentes restent canonicalisées sans retrait de capacité. + +## Modifications + +### Version workspace + +```text +0.2.3-pre.7 -> 0.2.3-pre.8 +``` + +### Preuve durable + +Ajout : + +```text +docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md +``` + +La matrice contient 37 lignes, une par wrapper courant typé. + +### Validation index + +`docs/validation/000-README.md` référence la nouvelle matrice. + +### Canarie release + +`crates/ksp-onchain-transport-lib/tests/release_completeness.rs` ajoute une canarie dédiée qui : + +- sélectionne exactement les descriptors `V0_2_1`, `V0_2_2` et `V0_2_3` ; +- exige exactement 37 méthodes ; +- exige `RuntimeStatus::Supported` ; +- exige `RetrySafe` pour Read/Simulation ; +- exige `NeverAfterDispatch` pour WriteSubmission ; +- vérifie que `getTransaction` conserve le marqueur de forme legacy deprecated. + +### Plan + +`docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md` enregistre le résultat de `pre.008` et confirme `pre.009` comme tranche de clôture finale. + +## Non-modifications intentionnelles + +Aucun wrapper, DTO wire/config/result, executor, retry policy, fixture HTTP, dépendance Cargo ou contrat public n'est modifié : l'audit ne révèle aucun manque à corriger. + +`CHANGELOG.md` et `ROADMAP.md` restent inchangés ; le changelog reste réservé à la release finale selon les règles du projet. + +## Validation opérateur attendue + +```bash +cargo fmt --all +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-onchain-transport-lib +``` + +Résultat attendu après ajout de la canarie : + +```text +182 unit tests +19 public API tests +14 release completeness tests +1 smoke Devnet ignored / opt-in +``` + +## Commit attendu + +```text +v0.2.3-pre.008 +``` + +## Suite + +`0.2.3-pre.009` : réaudit final, canaries/smoke opt-in si pertinent, README/USAGE, matrice finale, validations complètes, archivage/nettoyage requis et prompt de démarrage `0.2.4 — HTTP Blocks/Economics`. diff --git a/docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md b/docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md index 653e9f5..beccf59 100644 --- a/docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md +++ b/docs/plans/010-V0_2_3_HTTP_TRANSACTIONS_PLAN.md @@ -1,5 +1,5 @@ - + # Plan `0.2.3` — HTTP Transactions @@ -629,6 +629,16 @@ Une prerelease intermédiaire peut être ajoutée si le volume réel d'une tranc tranche de clôture en remédiation fonctionnelle tardive. La dernière prerelease reste une tranche de clôture documentaire/validation et ne doit pas devenir une implémentation massive tardive. +## Résultat de `pre.008` — réaudit rétroactif `KSP-TRANSPORT-007` + +Le réaudit rétroactif a été exécuté sur les **37 wrappers HTTP typés courants** livrés par `0.2.1`, `0.2.2` et `0.2.3-pre.007` : 4 foundation, 22 Accounts/Tokens/Cluster et 11 Transactions. La matrice durable est conservée dans `docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`. + +Le contrôle croise la documentation HTTP Solana courante avec Agave `v4.2.1`, génération recommandée pour adoption générale Mainnet-beta le 10 août 2026 et dont les activations Mainnet-beta ont commencé le 17 août 2026. `master` est déjà en `4.3.0-alpha`, mais n'est pas retenu comme contrat stable de cette release. + +Verdict : **aucune possibilité RPC supportée n'est manquante dans les 37 wrappers audités**. Les extensions runtime déjà prises en charge par KSP (`binary`, `sortResults`, `tokenAccountState`, `clientId`, `inflationRewardsCommissionBps`, `recentBlockhash`, champs riches de simulation, `transactionIndex`, etc.) sont conservées même lorsqu'elles ne sont pas toutes détaillées dans la page publique Solana. Les syntaxes strictement équivalentes peuvent rester canonicalisées conformément à `KSP-TRANSPORT-007`. + +Aucune remédiation fonctionnelle artificielle n'est donc introduite en `pre.008`. La tranche ajoute une preuve durable et une canarie nommée couvrant exactement les 37 descriptors courants de `0.2.1` à `0.2.3`, tout en préservant la forme legacy dépréciée de `getTransaction`. La clôture reste déplacée à `pre.009`. + ## Critères de clôture de `0.2.3` La release ne peut être candidate stable que si : diff --git a/docs/validation/000-README.md b/docs/validation/000-README.md index beadab5..e20b327 100644 --- a/docs/validation/000-README.md +++ b/docs/validation/000-README.md @@ -1,5 +1,5 @@ - + # Validations KSP @@ -13,3 +13,4 @@ Documents : - [`002-V0_2_0_SERIES_PLANNING.md`](002-V0_2_0_SERIES_PLANNING.md) — matrice finale de la release stable `0.2.0`, avec audit de cohérence et preuves opérateur de `pre.003`. - [`003-V0_2_1_ONCHAIN_HTTP.md`](003-V0_2_1_ONCHAIN_HTTP.md) — matrice de clôture de `0.2.1 — HTTP Solana foundation`, registry 52+14, résilience, Config -> Transport, quatre canaris et smoke Devnet opt-in. - [`004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md`](004-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER.md) — matrice finale validée de `0.2.2`, 22 wrappers Accounts/Tokens/Cluster, canaries 52+14, graphes Cargo, smoke Devnet Transport pur, smoke historique Config -> Transport et préparation de `0.2.3`. +- [`005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md`](005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md) — réaudit rétroactif de complétude `KSP-TRANSPORT-007` des 37 wrappers HTTP typés livrés de `0.2.1` à `0.2.3-pre.007`, avec preuves Solana/Agave et verdict méthode par méthode. diff --git a/docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md b/docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md new file mode 100644 index 0000000..f150f1a --- /dev/null +++ b/docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md @@ -0,0 +1,137 @@ + + + +# Réaudit rétroactif `KSP-TRANSPORT-007` — HTTP `0.2.1` à `0.2.3` + +## Objet + +Cette matrice est la preuve durable du réaudit rétroactif demandé par `0.2.3-pre.008`. Elle applique explicitement `KSP-TRANSPORT-007` aux **37 wrappers HTTP typés courants** livrés entre `0.2.1` et `0.2.3-pre.007` : + +```text +0.2.1 4 wrappers Foundation +0.2.2 5 Accounts + 5 Tokens + 12 Cluster = 22 wrappers +0.2.3 11 Transactions +Total 37 wrappers courants typés +``` + +Le contrôle porte sur : paramètres obligatoires et optionnels, champs de configuration, overloads/variantes courants, formes legacy encore supportées, contraintes déterministes connues, formes de réponse, `null`/omissions significatives et extensions runtime retenues. + +## Sources normatives retenues + +Audit effectué le **18 août 2026**. + +Sources principales : + +- documentation HTTP Solana courante : ; +- Agave `v4.2.1`, `rpc/src/rpc.rs` : ; +- Agave `v4.2.1`, `rpc-client-types/src/config.rs` : ; +- Agave `v4.2.1`, `rpc-client-types/src/response.rs` : ; +- Agave `v4.2.1`, `transaction-status-client-types/src/lib.rs` : . + +Le choix de `v4.2.1` est volontaire : la branche `v4.2` est la génération recommandée pour adoption générale Mainnet-beta depuis le 10 août 2026 et ses activations Mainnet-beta ont commencé le 17 août 2026. Le `master` Agave est déjà en `4.3.0-alpha` et n'est pas retenu comme contrat stable pour cette release. + +La documentation publique n'énumère pas toujours toutes les extensions runtime. Lorsqu'Agave `v4.2.1` expose une possibilité supplémentaire supportée, KSP la conserve conformément à `KSP-TRANSPORT-007`. + +## Verdict global + +**Conforme sans remédiation fonctionnelle.** Aucun paramètre, champ de config, overload, forme legacy encore supportée ou variante de réponse pertinente n'est manquant dans les 37 wrappers audités. + +Les extensions runtime déjà présentes dans KSP restent nécessaires, notamment : + +- `binary` pour les formes Account/Transaction legacy encore comprises par Agave ; +- `sortResults` sur les configs runtime concernées ; +- filtre `tokenAccountState` de `getProgramAccounts` ; +- `clientId` et endpoints étendus de `getClusterNodes` ; +- `inflationRewardsCommissionBps` de `getVoteAccounts` ; +- `transactionIndex` pour signatures/transaction confirmée ; +- `recentBlockhash` de `requestAirdrop` ; +- résultat riche de `simulateTransaction`, y compris balances, token balances, fee et loaded addresses. + +Les syntaxes strictement équivalentes restent canonicalisées lorsque cela ne retire aucune capacité. Exemple : l'absence de config et un objet config vide ne nécessitent pas deux APIs publiques distinctes lorsqu'elles ont le même effet RPC. La forme bare encoding dépréciée de `getTransaction`, qui n'est pas strictement équivalente du point de vue du contrat historique, reste au contraire exposée séparément et marquée deprecated. + +## Matrice méthode par méthode + +| Release | Méthode | Requête auditée / points sensibles | Réponse auditée / points sensibles | Verdict | +|---------|-------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|----------| +| 0.2.1 | `getBalance` | pubkey + `commitment/minContextSlot` | contexte + `u64` | Conforme | +| 0.2.1 | `getGenesisHash` | aucun paramètre | hash string | Conforme | +| 0.2.1 | `getHealth` | aucun paramètre | `ok` ou erreur RPC de santé | Conforme | +| 0.2.1 | `getVersion` | aucun paramètre | `solana-core`, `feature-set` | Conforme | +| 0.2.2 | `getAccountInfo` | pubkey + encoding/dataSlice/commitment/minContextSlot ; encodings docs + legacy runtime | `Account` ou `null`, data tuple/jsonParsed, `space` | Conforme | +| 0.2.2 | `getLargestAccounts` | commitment/filter + extension runtime `sortResults` | contexte + liste address/lamports | Conforme | +| 0.2.2 | `getMinimumBalanceForRentExemption` | data length + commitment | `u64` | Conforme | +| 0.2.2 | `getMultipleAccounts` | jusqu'à 100 pubkeys + config Account complète | ordre conservé + `null` positionnels + Account complet | Conforme | +| 0.2.2 | `getProgramAccounts` | config Account + filters dataSize/memcmp/tokenAccountState + withContext + sortResults | array nu ou contexte selon `withContext` | Conforme | +| 0.2.2 | `getTokenAccountBalance` | token account + commitment | contexte + amount/decimals/uiAmount/uiAmountString | Conforme | +| 0.2.2 | `getTokenAccountsByDelegate` | delegate + selector exclusif mint/programId + config Account complète | contexte + keyed accounts | Conforme | +| 0.2.2 | `getTokenAccountsByOwner` | owner + selector exclusif mint/programId + config Account complète | contexte + keyed accounts | Conforme | +| 0.2.2 | `getTokenLargestAccounts` | mint + commitment | contexte + ordered token account balances | Conforme | +| 0.2.2 | `getTokenSupply` | mint + commitment | contexte + token amount complet | Conforme | +| 0.2.2 | `getClusterNodes` | aucun paramètre | champs documentés + extensions runtime optionnelles : gossip/rpc/pubsub/tpu/tvu/repair/quic/forwards/vote/version/featureSet/clientId | Conforme | +| 0.2.2 | `getEpochInfo` | commitment/minContextSlot | absoluteSlot/blockHeight/epoch/slotIndex/slotsInEpoch/transactionCount nullable | Conforme | +| 0.2.2 | `getEpochSchedule` | aucun paramètre | cinq champs schedule | Conforme | +| 0.2.2 | `getHighestSnapshotSlot` | aucun paramètre | full + incremental nullable ; erreur RPC absence snapshot | Conforme | +| 0.2.2 | `getIdentity` | aucun paramètre | pubkey identité | Conforme | +| 0.2.2 | `getLeaderSchedule` | current epoch ou slot ; config identity/commitment ; overload config-only/slot+config canonicalisé explicitement | map identité -> indices ou `null` | Conforme | +| 0.2.2 | `getMaxRetransmitSlot` | aucun paramètre | `u64` | Conforme | +| 0.2.2 | `getMaxShredInsertSlot` | aucun paramètre | `u64` | Conforme | +| 0.2.2 | `getSlot` | commitment/minContextSlot | `u64` | Conforme | +| 0.2.2 | `getSlotLeader` | commitment/minContextSlot | pubkey | Conforme | +| 0.2.2 | `getSlotLeaders` | start slot + limit `1..=5000` | ordered pubkeys | Conforme | +| 0.2.2 | `getVoteAccounts` | commitment/votePubkey/keepUnstakedDelinquents/delinquentSlotDistance | current+delinquent, epochCredits, commission + inflationRewardsCommissionBps optionnel | Conforme | +| 0.2.3 | `getFeeForMessage` | message base64 opaque + commitment/minContextSlot | contexte + fee `u64` ou `null` | Conforme | +| 0.2.3 | `getLatestBlockhash` | commitment/minContextSlot | contexte + blockhash/lastValidBlockHeight | Conforme | +| 0.2.3 | `getRecentPrioritizationFees` | liste optionnelle de comptes, max 128 | liste ordonnée slot/prioritizationFee | Conforme | +| 0.2.3 | `getSignaturesForAddress` | address + before/until/limit `1..=1000`/commitment/minContextSlot | newest-first ; err/memo/blockTime/confirmationStatus/transactionIndex optionnels | Conforme | +| 0.2.3 | `getSignatureStatuses` | jusqu'à 256 signatures + searchTransactionHistory ; liste vide acceptée runtime | contexte + `null` positionnels + status legacy/current | Conforme | +| 0.2.3 | `getTransaction` | forme objet moderne complète + bare encoding legacy deprecated ; encodings binary/base58/base64/json/jsonParsed ; confirmed/finalized ; maxSupportedTransactionVersion | `null` ou transaction binaire/JSON/jsonParsed ; meta/version/transactionIndex conservés losslessly | Conforme | +| 0.2.3 | `getTransactionCount` | commitment/minContextSlot | `u64` | Conforme | +| 0.2.3 | `isBlockhashValid` | blockhash opaque + commitment/minContextSlot | contexte + bool | Conforme | +| 0.2.3 | `requestAirdrop` | recipient + lamports + commitment + extension runtime recentBlockhash | signature string | Conforme | +| 0.2.3 | `sendTransaction` | transaction opaque base58/base64 + skipPreflight/preflightCommitment/maxRetries/minContextSlot | signature string ; no-resend KSP après dispatch ambigu | Conforme | +| 0.2.3 | `simulateTransaction` | base58/base64 + commitment/replaceRecentBlockhash/sigVerify/minContextSlot/innerInstructions/accounts ; encodings comptes supportés ; invariant sigVerify/replace | contexte + résultat riche complet et états null/omitted | Conforme | + +## Contrôles transverses + +### Encodings Account + +KSP expose `binary`, `base58`, `base64`, `jsonParsed` et `base64+zstd`. Les pages Solana courantes mettent surtout en avant `base58/base64/base64+zstd/jsonParsed`, mais Agave conserve la variante `Binary` pour compatibilité. La sous-config `accounts` de `simulateTransaction` rejette spécifiquement `binary/base58`; KSP applique cette contrainte avant I/O tout en conservant les autres encodings supportés. + +### Overloads et formes legacy + +- `getLeaderSchedule` conserve les formes current epoch, slot, config et slot+config via un enum de requête non ambigu ; +- `getTransaction` conserve la forme moderne et le bare encoding legacy séparé, explicitement deprecated ; +- les configs vides/absentes strictement équivalentes sont canonicalisées sans perte de capacité. + +### Cardinalités + +Les bornes déterministes connues et testables sans décodage métier sont déjà appliquées avant I/O : + +```text +getMultipleAccounts <= 100 +getProgramAccounts filters <= 4 +memcmp raw bytes <= 128 bytes +getSlotLeaders 1..=5000 +getRecentPrioritizationFees <= 128 comptes +getSignaturesForAddress.limit 1..=1000 +getSignatureStatuses <= 256 signatures +``` + +La limite de `simulateTransaction.accounts.addresses` dépend du nombre de comptes de la transaction sérialisée et reste donc une validation runtime : Transport ne décode pas la transaction uniquement pour reproduire cette vérification. + +### Résilience + +Les 37 descriptors restent `Supported`. Les lectures et la simulation restent `RetrySafe`. `requestAirdrop` et `sendTransaction` restent `WriteSubmission / NeverAfterDispatch`, avec retry autorisé uniquement si Transport prouve `NotDispatched`. + +## Remédiations de `pre.008` + +Aucune remédiation fonctionnelle n'est requise par cet audit. Ajouter artificiellement des variantes ou des DTOs aurait au contraire créé des doublons sans possibilité RPC supplémentaire. + +`pre.008` ajoute donc uniquement : + +- cette matrice de preuve durable ; +- une canarie release explicitement nommée `KSP-TRANSPORT-007` couvrant les 37 descriptors `0.2.1`–`0.2.3` et leurs classes de retry ; +- la synchronisation du plan `0.2.3` ; +- l'incrément technique `0.2.3-pre.8`, car la canarie Rust participe au build/test. + +La tranche suivante reste `pre.009`, réservée à la clôture finale, la documentation utilisateur, les canaries/smokes pertinents, la validation complète et le prompt de démarrage `0.2.4`.