From 8096e6f07beba12b26c3d6fe7af66684376a4cd4 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Tue, 1 Sep 2026 14:24:22 +0200 Subject: [PATCH] v0.3.6-pre.006-fix.001 --- Cargo.toml | 4 +- crates/ksp-job-backfill-lib/src/conversion.rs | 16 ++- .../unit_tests/conversion.rs | 8 +- deltas/0.3.6/pre.006-fix.001.md | 128 ++++++++++++++++++ .../plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md | 12 +- .../validation/023-V0_3_6_JOB_API_BACKFILL.md | 28 ++-- 6 files changed, 173 insertions(+), 23 deletions(-) create mode 100644 deltas/0.3.6/pre.006-fix.001.md diff --git a/Cargo.toml b/Cargo.toml index e8617f3..fe9f228 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 402 +# version: 403 [workspace] resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.3.6-pre.6" +version = "0.3.6-pre.6.fix.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-job-backfill-lib/src/conversion.rs b/crates/ksp-job-backfill-lib/src/conversion.rs index 415eea4..af326b8 100644 --- a/crates/ksp-job-backfill-lib/src/conversion.rs +++ b/crates/ksp-job-backfill-lib/src/conversion.rs @@ -1,5 +1,5 @@ // file: crates/ksp-job-backfill-lib/src/conversion.rs -// version: 1 +// version: 2 use sha2::Digest; // rust-rules: trait-import @@ -15,6 +15,11 @@ const RAW_TRANSACTION_PROTOCOL_CODE: &str = "solana.http.json_rpc"; /// Complete in-memory RAW transaction acquisition ready for the later Store persistence tranche. #[derive(Debug)] pub struct BackfillRawAcquisition { + inner: Box, +} + +#[derive(Debug)] +struct BackfillRawAcquisitionInner { transaction: ksp_store_lib::RawTransaction, observation: ksp_store_lib::RawTransactionObservation, } @@ -23,19 +28,20 @@ impl BackfillRawAcquisition { /// Returns the canonical RAW transaction produced from the typed Transport response. #[must_use] pub const fn transaction(&self) -> &ksp_store_lib::RawTransaction { - return &self.transaction; + return &(*self.inner).transaction; } /// Returns the acquisition observation whose provenance records the actual successful endpoint. #[must_use] pub const fn observation(&self) -> &ksp_store_lib::RawTransactionObservation { - return &self.observation; + return &(*self.inner).observation; } /// Consumes the in-memory acquisition into the canonical transaction and its observation. #[must_use] pub fn into_parts(self) -> (ksp_store_lib::RawTransaction, ksp_store_lib::RawTransactionObservation) { - return (self.transaction, self.observation); + let inner = *self.inner; + return (inner.transaction, inner.observation); } } @@ -208,7 +214,7 @@ fn convert_available_fields( let observation_key = observation_key(request, &reference, provider, endpoint); let transaction = ksp_store_lib::RawTransaction::new(reference.clone(), fields.slot, block_time, payload); let observation = ksp_store_lib::RawTransactionObservation::new(observation_key, reference, provenance); - return std::result::Result::Ok(BackfillRawAcquisition { transaction, observation }); + return std::result::Result::Ok(BackfillRawAcquisition { inner: Box::new(BackfillRawAcquisitionInner { transaction, observation }) }); } fn convert_block_time(value: std::option::Option) -> ksp_core_lib::Result> { diff --git a/crates/ksp-job-backfill-lib/unit_tests/conversion.rs b/crates/ksp-job-backfill-lib/unit_tests/conversion.rs index 5dcafe9..ffc1746 100644 --- a/crates/ksp-job-backfill-lib/unit_tests/conversion.rs +++ b/crates/ksp-job-backfill-lib/unit_tests/conversion.rs @@ -1,5 +1,5 @@ // file: crates/ksp-job-backfill-lib/unit_tests/conversion.rs -// version: 1 +// version: 2 fn signature_text() -> std::option::Option { return match crate::BackfillSignature::new("1".repeat(64)) { @@ -293,3 +293,9 @@ fn pre_006_missing_outcome_contains_only_network_scoped_reference() { assert_eq!(outcome.reference().signature().as_bytes(), &[0_u8; 64]); return; } + +#[test] +fn pre_006_fix_001_raw_acquisition_uses_one_private_indirection() { + assert_eq!(std::mem::size_of::(), std::mem::size_of::(),); + return; +} diff --git a/deltas/0.3.6/pre.006-fix.001.md b/deltas/0.3.6/pre.006-fix.001.md new file mode 100644 index 0000000..fe53fab --- /dev/null +++ b/deltas/0.3.6/pre.006-fix.001.md @@ -0,0 +1,128 @@ + + + +# Delta `0.3.6-pre.006-fix.001` — indirection privée de l’acquisition RAW + +## Base requise + +```text +0.3.6-pre.006 appliquée +workspace.package.version = 0.3.6-pre.6 +``` + +Le gate opérateur fourni pour `pre.006` confirme : + +```text +cargo fmt --all PASS +python3 scripts/audit_rust_workspace_rules.py PASS / clean +python3 scripts/audit_markdown_tables.py ... PASS / clean (264 tables / 149 fichiers) +cargo check --workspace PASS +cargo clippy --workspace --all-targets PASS avec warning clippy::large_enum_variant +cargo test -p ksp-job-backfill-lib PASS + unitaires 19 PASS + dependency_boundary 2 PASS + public_api 3 PASS + release_completeness 2 PASS +cargo tree -p ksp-job-backfill-lib --edges normal exécuté +cargo tree -p ksp-job-backfill-lib -e features exécuté +``` + +## Objectif + +Supprimer le warning `clippy::large_enum_variant` sans masquer le lint et sans changer la forme publique de `BackfillHydrationOutcome`. + +## Cause exacte + +`BackfillHydrationOutcome` expose deux variantes : + +```rust +Available(BackfillRawAcquisition), +Missing(ksp_store_lib::RawTransactionReference), +``` + +Le gate mesure au moins environ 560 octets pour `Available` contre environ 88 octets pour `Missing`. La différence provient de l’embarquement direct de la transaction RAW et de son observation dans `BackfillRawAcquisition`. + +## Correctif + +La structure publique `BackfillRawAcquisition` conserve ses méthodes et reste la charge utile directe de `Available`, mais ses deux champs privés sont regroupés dans un état privé détenu par une unique `Box`. + +Ainsi : + +- l’API publique `Available(BackfillRawAcquisition)` ne change pas ; +- aucun `Box` n’apparaît dans la signature publique de l’enum ; +- `transaction()`, `observation()` et `into_parts()` gardent leurs signatures ; +- une seule allocation est introduite par acquisition disponible ; +- `Missing(reference)` reste sans allocation et sans provenance fabriquée ; +- aucun `#[allow(clippy::large_enum_variant)]` n’est ajouté. + +Une canarie unitaire vérifie que `BackfillRawAcquisition` conserve la taille d’un pointeur, ce qui verrouille l’indirection privée destinée à empêcher la régression de taille. + +## Version + +Le fix modifie du Rust : + +```text +workspace.package.version = 0.3.6-pre.6.fix.1 +delivery = 0.3.6-pre.006-fix.001 +commit = v0.3.6-pre.006-fix.001 +``` + +Aucun tag prerelease. + +## Fichiers ajoutés + +```text +deltas/0.3.6/pre.006-fix.001.md +``` + +## Fichiers modifiés + +```text +Cargo.toml +crates/ksp-job-backfill-lib/src/conversion.rs +crates/ksp-job-backfill-lib/unit_tests/conversion.rs +docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md +docs/validation/023-V0_3_6_JOB_API_BACKFILL.md +``` + +## Versions d’en-tête + +```text +Cargo.toml 402 -> 403 +crates/ksp-job-backfill-lib/src/conversion.rs 1 -> 2 +crates/ksp-job-backfill-lib/unit_tests/conversion.rs 1 -> 2 +docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md 10 -> 11 +docs/validation/023-V0_3_6_JOB_API_BACKFILL.md 10 -> 11 +``` + +Le présent delta commence à `version: 1`. + +## Invariants préservés + +- identité logique transactionnelle toujours `(RawNetworkId, signature)` ; +- provider/endpoint/protocole restent uniquement de la provenance d’acquisition ; +- format RAW v1, canonicalisation JSON, SHA-256 et block time inchangés ; +- chemin observé `getTransaction` et paramètres Transport inchangés ; +- `Missing` reste structurellement sans provenance ; +- aucune persistance Store, checkpoint, concurrence ou snapshot ajoutés ; +- aucune nouvelle dépendance, feature, crate ou API publique ; +- README, USAGE, CHANGELOG, ROADMAP et prompt restent fermés. + +## Gate opérateur demandé + +```bash +cargo fmt --all +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.6 +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-job-backfill-lib +cargo tree -p ksp-job-backfill-lib --edges normal +cargo tree -p ksp-job-backfill-lib -e features +``` + +Résultat attendu : **20 tests unitaires + 7 canaries d’intégration**, aucun warning `large_enum_variant`, et graphe de dépendances inchangé. + +## Questions ouvertes + +Aucune. `pre.007` reste interdit tant que le gate de ce fix n’est pas warning-free. diff --git a/docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md b/docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md index 9c84c49..d6d368d 100644 --- a/docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md +++ b/docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md @@ -1,5 +1,5 @@ - + # Plan v0.3.6 — Job API et premier backfill RAW @@ -450,13 +450,19 @@ Le gate opérateur de `pre.005` confirme `cargo fmt`, les audits Rust/Markdown, ### `pre.006` — Conversion RAW v1 et provenance -**Statut : matérialisé ; gate opérateur à rejouer.** +**Statut : matérialisé ; gate fonctionnel vert avec un warning Clippy.** Budget cible : **15-20 min**. Entrée : candidats déterministes et gate `pre.005-fix.001` vert. La tranche ajoute une conversion RAW v1 strictement en mémoire : `BackfillSignature::to_raw_transaction_signature` décode Base58 vers exactement 64 octets sans SDK Solana ni nouvelle dépendance Base58 ; `hydrate_backfill_candidate` appelle uniquement `HttpTransportPool::get_transaction_observed` avec `base64`, engagement explicite et `maxSupportedTransactionVersion = 0`. Un résultat `null` devient `BackfillHydrationOutcome::Missing(RawTransactionReference)` et ne contient structurellement aucune provenance. Le payload `ksp.solana.raw_transaction` version `1` conserve la transaction comme tuple `[data, "base64"]`, omet `slot` et `blockTime`, préserve les états omitted/null/value de `meta`, `version` et `transactionIndex`, et canonise récursivement les objets JSON par tri lexical des clés avant calcul SHA-256. Les block times négatifs ou hors plage sont rejetés. Une acquisition disponible produit `RawTransaction` et `RawTransactionObservation` avec provider, protocole `solana.http.json_rpc`, méthode `getTransaction`, endpoint victorieux, engagement, `JobId` et timestamp de réception. La clé d'observation est domain-separated et dépend du JobId, fingerprint, signature, provider, endpoint, engagement et version du contrat ; changer d'endpoint crée donc une observation distincte sans changer l'identité `(network, signature)`. -La tranche matérialise 8 nouveaux tests unitaires de conversion, portant le total Backfill à 19 unitaires, et une canarie publique supplémentaire, portant les canaries d'intégration à 7. Aucun appel de persistance Store, checkpoint, concurrence runtime ou snapshot concret n'est ouvert ; ces responsabilités restent aux tranches suivantes. +Le gate opérateur exécute avec succès 19 unitaires et 7 canaries d'intégration, ainsi que `cargo check` et les audits. Clippy reste toutefois non warning-free à cause de `clippy::large_enum_variant` : l'acquisition disponible est beaucoup plus volumineuse que la référence `Missing`. Aucun appel de persistance Store, checkpoint, concurrence runtime ou snapshot concret n'est ouvert ; ces responsabilités restent aux tranches suivantes. + +#### `pre.006-fix.001` — Indirection privée de l'acquisition RAW + +**Statut : matérialisé ; gate opérateur à rejouer.** + +Le fix conserve exactement la forme publique `BackfillHydrationOutcome::Available(BackfillRawAcquisition)` et place uniquement les champs privés transaction + observation derrière une unique `Box`. Aucun `#[allow]` n'est utilisé et aucun `Box` n'apparaît dans l'enum public. Les getters et `into_parts` restent identiques ; une canarie unitaire verrouille la taille pointeur de `BackfillRawAcquisition`. La version workspace devient `0.3.6-pre.6.fix.1`. ### `pre.007` — Persistance Store et idempotence diff --git a/docs/validation/023-V0_3_6_JOB_API_BACKFILL.md b/docs/validation/023-V0_3_6_JOB_API_BACKFILL.md index 6f92cf9..c5b66d3 100644 --- a/docs/validation/023-V0_3_6_JOB_API_BACKFILL.md +++ b/docs/validation/023-V0_3_6_JOB_API_BACKFILL.md @@ -1,5 +1,5 @@ - + # Validation v0.3.6 — Job API et premier backfill RAW @@ -139,21 +139,23 @@ Aucune entrée absolue, traversée, avec séparateur inversé ou lien symbolique ## 10. RAW v1 et provenance -`pre.006` matérialise cette surface et ses tests statiques/unitaires ; les cases ci-dessous restent ouvertes jusqu'au gate Cargo opérateur de la tranche. +`pre.006` matérialise cette surface et ses tests statiques/unitaires. Le gate opérateur confirme les audits, `cargo check`, les 19 unitaires et les 7 canaries, mais Clippy émet `clippy::large_enum_variant` sur `BackfillHydrationOutcome` : `Available(BackfillRawAcquisition)` contient au moins 560 octets alors que `Missing(reference)` en contient environ 88. Le résultat fonctionnel est vert, mais la tranche n'est pas considérée warning-free. + +`pre.006-fix.001` conserve l'API publique de l'enum et introduit une seule indirection privée dans `BackfillRawAcquisition`. Aucun `#[allow]` n'est ajouté. Les getters et `into_parts` conservent leurs signatures, et une canarie vérifie que `BackfillRawAcquisition` reste de la taille d'un pointeur. Le gate Cargo du fix reste à rejouer par l'opérateur. - [X] Identité logique future auditée : transaction/signature scoping par `RawNetworkId`, jamais par rôle/provider/endpoint/protocole. - [X] Le Store PostgreSQL actuel est mono-réseau via `ksp_store_identity`; un futur backend multi-réseaux devra préserver `(network, signature)` par clé/partition équivalente. -- [ ] Format `ksp.solana.raw_transaction`, version `1`, figé. -- [ ] `getTransaction` demandé en `base64` avec version maximale `0`. -- [ ] Bytes JSON compacts déterministes et golden tests stables. -- [ ] Transaction binaire conservée sans décodage métier. -- [ ] `meta`, `version` et `transactionIndex` distinguent absent, `null` et valeur. -- [ ] Slot et block time non dupliqués dans le payload. -- [ ] Block time négatif rejeté explicitement. -- [ ] Hash SHA-256 et taille calculés sur les bytes exacts. -- [ ] Provenance contient fournisseur, protocole, méthode, endpoint sûr, engagement et réception. +- [X] Format `ksp.solana.raw_transaction`, version `1`, figé. +- [X] `getTransaction` demandé en `base64` avec version maximale `0`. +- [X] Bytes JSON compacts déterministes et golden tests stables. +- [X] Transaction binaire conservée sans décodage métier. +- [X] `meta`, `version` et `transactionIndex` distinguent absent, `null` et valeur. +- [X] Slot et block time non dupliqués dans le payload. +- [X] Block time négatif rejeté explicitement. +- [X] Hash SHA-256 et taille calculés sur les bytes exacts. +- [X] Provenance contient fournisseur, protocole, méthode, endpoint sûr, engagement et réception. - [ ] Clé d'observation domain-separated et déterministe. -- [ ] Endpoint différent produit une nouvelle observation légitime. +- [X] Endpoint différent produit une nouvelle observation légitime. ## 11. Persistance Store @@ -198,6 +200,8 @@ Aucune entrée absolue, traversée, avec séparateur inversé ou lien symbolique - [ ] Aucun retour de dépendance vers Job depuis les couches basses. - [X] Versions/features auditées : aucune nouvelle version externe ; `sha2` et `tokio` réutilisent les entrées workspace existantes, Tokio étant dev-only en `pre.005`. - [X] `pre.005` matérialise 11 tests unitaires et 6 canaries d’intégration ; le gate opérateur les exécute tous avec succès. +- [X] `pre.006` matérialise 19 tests unitaires et 7 canaries d’intégration ; le gate opérateur les exécute tous avec succès, avec uniquement le warning Clippy corrigé par `pre.006-fix.001`. +- [ ] `cargo clippy --workspace --all-targets` warning-free sur `pre.006-fix.001`. - [ ] `cargo fmt --all -- --check` vert. - [X] `scripts/audit_rust_workspace_rules.py` vert sur `pre.005` dans l'environnement d'assemblage et dans le gate opérateur. - [X] `scripts/audit_markdown_tables.py` vert sur `pre.005` dans le gate opérateur (264 tables / 147 fichiers, delta inclus).