# Delta `0.3.10-pre.002` — fondation RAW Transaction commune ## Base requise ```text 0.3.10-pre.001 workspace.package.version = 0.3.10-pre.1 ``` Le gate opérateur communiqué pour `pre.001` passe `cargo fmt --all`, les audits Rust/Markdown, `cargo check --workspace` et Clippy workspace `--all-targets --all-features -- -D warnings`. Le message ne fournit pas de `cargo test` supplémentaire ; aucun test non communiqué n’est déclaré exécuté. ## Objectif Créer uniquement `ksp-raw-transaction-lib` comme lower-layer commune de canonicalisation RAW Transaction v1 : matériau source-neutral, parser de signature, canonical JSON, SHA-256 et assemblage transaction/observation. Aucun Worker et aucune migration du Backfill dans cette tranche. ## Version Cette tranche est une prerelease non-fix : ```text workspace.package.version = 0.3.10-pre.2 ``` Le `Cargo.toml` racine passe du header `490` au header `491` et ajoute `crates/ksp-raw-transaction-lib` aux membres du workspace. ## Correction normative du plan `pre.001` Le sizing `pre.001` avait retenu `ksp-store-lib(default-features=false)` pour la common crate. La relecture au moment de matérialiser la frontière révèle une règle plus spécifique : ```text DEP-PIPE-006 Le pipeline raw ingestion peut dépendre des modèles homogènes de ksp-onchain-transport-lib et de ksp-store-api, mais pas de ksp-store-lib. ``` La dépendance est donc corrigée vers `ksp-store-api`. Cette correction ne change aucun invariant RAW ; elle retire au contraire la façade/runtime Store de la lower-layer réutilisable. ## Dépendances exactes ```text ksp-raw-transaction-lib -> ksp-core-lib -> ksp-store-api -> serde_json -> sha2 ``` Absents de la crate : ```text ksp-store-lib ksp-store-postgres-lib ksp-onchain-transport-lib ksp-config-lib ksp-job-api ksp-job-backfill-lib ksp-worker-api Tokio / futures provider SDK ``` ## Surface publique ```text RAW_TRANSACTION_FORMAT_ID = ksp.solana.raw_transaction RAW_TRANSACTION_FORMAT_VERSION = 1 MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES = 64 MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES = 88 RawTransactionMaterial RawTransactionWireField RawTransactionVersion RawTransactionAcquisition parse_raw_transaction_signature(...) canonicalize_raw_transaction(...) assemble_raw_transaction_acquisition(...) ERROR_CODE_RAW_TRANSACTION_CANONICALIZATION_INVALID ERROR_CODE_RAW_TRANSACTION_MATERIAL_INVALID ERROR_CODE_RAW_TRANSACTION_SIGNATURE_INVALID ``` Tous les modules restent privés et les éléments consommables sont réexportés au crate-root. ## Contrat matérialisé ### Signature Le parser reçoit un texte Base58 borné de `64..=88` octets et n’accepte que les représentations décodant exactement vers `64` octets. Aucun Solana SDK ou codec externe n’est ajouté. Les erreurs ne recopient jamais la signature hostile ; seules les longueurs numériques sûres peuvent apparaître en contexte. ### Matériau source-neutral `RawTransactionMaterial::binary_base64(...)` reçoit : ```text network signature canonique 64 bytes slot u64 block_time Option transaction data binaire Base64 déjà obtenu de la source meta omitted/null/value version omitted/null/value (legacy ou u8) transactionIndex omitted/null/value u32 ``` Aucun type Transport/provider n’entre dans la common crate. La représentation interne peut être étendue ultérieurement pour Yellowstone uniquement lorsqu’une parité RAW v1 sera démontrée. ### Canonicalisation RAW v1 La sortie conserve exactement : ```text ordre top-level : transaction -> meta -> version -> transactionIndex transaction = [data, "base64"] tri récursif des clés d’objets JSON ordre des arrays conservé omitted != null != value block_time hors payload, converti en RawTimestamp SHA-256 sur les bytes canoniques exacts format id/version gelés ``` Golden verrouillé : ```text bytes = {"transaction":["AQID","base64"],"meta":{"a":{"x":null,"y":true},"z":1},"version":"legacy","transactionIndex":7} byte_len = 112 sha256 = 220792d2b15d262fda242cb220774ee9ddeffebf04dcfadabcf8ef76a9b1a7c3 ``` ### Observation producer-owned `assemble_raw_transaction_acquisition(...)` reçoit la `RawObservationKey` déjà choisie par le producteur et construit l’observation sur la référence exacte de la transaction. Aucun domaine de clé Backfill ou Worker n’est introduit dans common. ## Tests ajoutés Tests unitaires : ```text signature exacte 64 bytes signature bornes / caractère Base58 invalide / overflow / longueur décodée non canonique golden bytes + hash RAW v1 omitted/null/value golden JSON récursif / arrays / escaping / nombres block_time négatif / overflow / maximum borne payload Debug material/wire redacted assemblage acquisition + observation key producer-owned ``` Tests d’intégration : ```text dependency boundary exacte absence runtime/Transport/Config/Job/Worker/backend consommation crate-root externe assemblage avec modèles Store API inventaire modules production absence de contrat Worker/Backfill/Transport dans la façade error codes stables signature hostile non recopiée ``` ## Fichiers ajoutés ```text crates/ksp-raw-transaction-lib/Cargo.toml crates/ksp-raw-transaction-lib/src/acquisition.rs crates/ksp-raw-transaction-lib/src/canonical.rs crates/ksp-raw-transaction-lib/src/error.rs crates/ksp-raw-transaction-lib/src/lib.rs crates/ksp-raw-transaction-lib/src/signature.rs crates/ksp-raw-transaction-lib/unit_tests/acquisition.rs crates/ksp-raw-transaction-lib/unit_tests/canonical.rs crates/ksp-raw-transaction-lib/unit_tests/signature.rs crates/ksp-raw-transaction-lib/tests/dependency_boundary.rs crates/ksp-raw-transaction-lib/tests/public_api.rs crates/ksp-raw-transaction-lib/tests/release_completeness.rs crates/ksp-raw-transaction-lib/tests/security_hardening.rs deltas/0.3.10/pre.002.md ``` ## Fichiers modifiés ```text Cargo.toml docs/plans/031-V0_3_10_RAW_TRANSACTION_INGEST_PLAN.md docs/validation/027-V0_3_10_RAW_TRANSACTION_INGEST.md ``` ## Fichiers supprimés Aucun. ## Documentation volontairement différée `README.md` et `USAGE.md` de la nouvelle crate ne sont pas finalisés dans cette tranche de fondation. La réconciliation version-neutral reste réservée au couloir documentaire `pre.015`, après parité cross-source, migration Backfill et freeze fonctionnelle. ## Validations exécutées dans l’environnement d’assemblage ```text python3 scripts/audit_rust_workspace_rules.py General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas Markdown table audit: clean (339 table(s), 754 file(s)) contrôle TOML : 20 membres workspace, nouvelle crate présente contrôle manifest common : dépendances exactes core/store-api/serde_json/sha2, aucune feature/dev/build dependency ``` L’environnement d’assemblage ne fournit ni `cargo`, ni `rustc`, ni `rustfmt`. Aucun gate Cargo de `pre.002` n’est donc déclaré PASS localement. ## 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 cargo check --workspace cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test -p ksp-raw-transaction-lib cargo tree -p ksp-raw-transaction-lib --edges normal cargo tree -p ksp-raw-transaction-lib -e features ``` ## Validations non exécutées localement ```text cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test -p ksp-raw-transaction-lib cargo tree -p ksp-raw-transaction-lib --edges normal cargo tree -p ksp-raw-transaction-lib -e features smokes live : non pertinents pour cette tranche purement déterministe ``` ## Décisions prises ```text RAW v1 reste unique et inchangé ksp-store-api remplace ksp-store-lib dans common pour conformité DEP-PIPE-006 RawObservationKey reste producer-owned aucun type Transport dans common aucun async/runtime dans common aucune migration Backfill avant pre.003 aucun Worker avant pre.007 selon le plan recalibré ``` ## Questions ouvertes Aucune question ne bloque `pre.003` après un gate opérateur vert. Les projections structurées WS/Helius/Yellowstone restent volontairement différées jusqu’aux tranches de parité prévues ; elles ne doivent pas modifier RAW v1 par anticipation.