diff --git a/Cargo.toml b/Cargo.toml index 253f014..6831ba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 489 +# version: 490 [workspace] resolver = "3" members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-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", "crates/ksp-worker-api"] [workspace.package] -version = "0.3.9" +version = "0.3.10-pre.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/deltas/0.3.10/pre.001.md b/deltas/0.3.10/pre.001.md new file mode 100644 index 0000000..e240e5c --- /dev/null +++ b/deltas/0.3.10/pre.001.md @@ -0,0 +1,263 @@ + + + +# Delta 0.3.10-pre.001 — audit/sizing RAW Transaction + Worker ingest + +## Base + +```text +archive : khadhroony-solana-project-v0.3.9.zip +SHA-256 : 41ef2589a11410aabfb329d387f0008e116006da60ada0802e5f72bc30d3466f +ZIP bytes : 7859118 +ZIP entries : 1855 +unzip -t : PASS +workspace members : 19 +workspace.package.version base : 0.3.9 +``` + +Le ZIP a été contrôlé sans path traversal/entrée absolue, symlink, `.git/`, `target/`, `node_modules/`, `Cargo.lock`, `.env` ou fichier de clé privée détecté. + +## Type de livraison + +```text +ksp-general-0.3.10-pre.001.zip +``` + +Le type `general` est obligatoire parce que `Cargo.toml` racine est synchronisé vers `0.3.10-pre.1` par `VER-ID-009`. L’archive d’échange ne doit contenir que les fichiers ajoutés/modifiés et le delta, conformément à `VER-ARCHIVE-004`. + +## Baseline exécutée avant modification + +```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 (332 table(s), 750 file(s)) +``` + +`cargo` n’est pas installé dans l’environnement d’assemblage. Aucun gate Cargo local n’est déclaré PASS. Le journal opérateur stable `0.3.9` reste une preuve externe distincte. + +## Objectif + +Exécuter le gate d’ouverture `0.3.10-pre.001` demandé par le prompt `029` : vérifier intégralement la base `v0.3.9`, auditer l’extraction RAW commune et les capabilities live, réévaluer `TR-B..TR-F`, fixer les frontières Common/Worker/Transport/Config/Store, puis dimensionner les tranches suivantes sans commencer l’implémentation lourde. + +## Mission exécutée + +`pre.001` reste une tranche de planification, conformément au prompt `029` : + +```text +lecture règles/architecture obligatoires +inventaire workspace/manifests/features +extraction RAW commune auditée +capability matrix Worker implementation-ready +TR-B..TR-F réévalués +fraîcheur Solana/Yellowstone/providers revalidée +runtime/source supervision décidés +continuité/gap repair décidés +snapshot concret décidé +Config/secrets boundary décidée +threat model et preuves définis +dependency graph cible fixé +prereleases redimensionnées +``` + +Aucune implémentation lourde des deux nouvelles crates n’est commencée. + +## Décisions principales + +### Common RAW + +```text +crate : ksp-raw-transaction-lib +RAW format : ksp.solana.raw_transaction v1 inchangé +common deps : ksp-core-lib + ksp-store-lib(default-features=false) + serde_json + sha2 +aucun Transport/Config/Job/Worker/runtime/backend +RawObservationKey reste producer-owned +Backfill conserve son observation key/job_id/scope_fingerprint/origin +``` + +Golden confirmé : + +```text +byte_len = 112 +sha256 = 220792d2b15d262fda242cb220774ee9ddeffebf04dcfadabcf8ef76a9b1a7c3 +``` + +Toute source full doit prouver une parité byte-for-byte avec RAW v1 avant persistence directe ; sinon elle reste discovery + hydration. + +### Worker concret + +```text +crate : ksp-worker-raw-transaction-ingest-lib +caller-owned Tokio runtime +Worker-owned source/supervisor tasks +bounded channels uniquement +multi-source simultané +Store idempotence comme vérité de convergence +observations distinctes conservées +content conflict terminal +repair borné au run frontier +reconnect != replay +aucun paramètre historique métier au start +``` + +### Transport gaps + +```text +TR-B confirmé : get_block_observed +TR-C confirmé/scindé : common material + adapters Worker + Transport change only if DTO lacks fidelity +TR-D confirmé : provenance durable full-material + source runtime snapshot +TR-E confirmé : reuse from_slot/replay info, aucun second Yellowstone client +TR-F réservé : EARLY seulement si protocole/accès/rôle RAW prouvés +``` + +### Config + +```text +aucun edge Worker -> Config +std.transport V3 actuel réutilisé +pas de nouveau document métier Worker imposé en 0.3.10 +adaptation Config seulement si un manque Transport concret l’exige +secrets restent Config-owned et redacted +``` + +## Fraîcheur externe + +Vérifié le 5 septembre 2026 : + +```text +yellowstone-grpc-proto latest = 12.7.0 (2026-08-29) +workspace stable = ^12.7 -> aucun bump initial +Yellowstone block from_slot replay a reçu un fix upstream en juillet 2026 -> smoke block replay obligatoire +Helius transactionSubscribe courant ; Helius blockSubscribe explicitement non supporté +Helius LaserStream replay 24 h documenté +PublicNode Yellowstone Mainnet/Testnet visible ; replay depth non prouvée +OrbitFlare gRPC Devnet disponible Free/Developer +QuickNode gRPC Scale+ ; port 443/x-token ; port 10000 sunset 2026-10-01 +Alchemy replay docs contradictoires 6000 vs 432000 slots -> aucune constante KSP +Jito ShredStream shutdown annoncé pour 2026-09-05 -> SUNSET, non retenu TR-F +``` + +## Plan recalibré + +```text +pre.002 common RAW foundation +pre.003 Backfill migration +pre.004 observed block + HTTP block material +pre.005 WS/Helius full parity +pre.006 Yellowstone parity +pre.007 Worker runtime foundation +pre.008 Yellowstone live/replay +pre.009 WS/HTTP live +pre.010 multi-source persistence/hardening +pre.011 gap repair +pre.012 Config/profiles + smokes accessibles +pre.013 EARLY si prouvé, sinon consolidation +pre.014 gate technique/live final +pre.015 réconciliation documentaire +pre.016 préparation publication +rel.001 stable +``` + +## Fichiers ajoutés + +```text +docs/plans/031-V0_3_10_RAW_TRANSACTION_INGEST_PLAN.md +docs/validation/027-V0_3_10_RAW_TRANSACTION_INGEST.md +deltas/0.3.10/pre.001.md +``` + +## Fichiers modifiés + +```text +Cargo.toml +``` + +`Cargo.toml` : + +```text +file version 489 -> 490 +workspace.package.version 0.3.9 -> 0.3.10-pre.1 +``` + +Ce bump est requis par `VER-ID-009` pour toute prerelease non-fix, même lorsque la tranche est documentaire. + +## Fichiers supprimés + +```text +aucun +``` + +## Validation après modification + +Audits statiques réellement exécutés après matérialisation de `pre.001` : + +```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), 753 file(s)) +``` + +Le premier passage Markdown post-modification a détecté 32 erreurs d’alignement uniquement dans les nouvelles tables. Elles ont été corrigées selon la règle KSP, puis le gate complet ci-dessus a été relancé jusqu’à PASS. + +La comparaison byte-à-byte contre le contenu du ZIP stable, après suppression du cache Python d’audit, donne exactement : + +```text +ajoutés : + deltas/0.3.10/pre.001.md + docs/plans/031-V0_3_10_RAW_TRANSACTION_INGEST_PLAN.md + docs/validation/027-V0_3_10_RAW_TRANSACTION_INGEST.md +modifié : + Cargo.toml +supprimé : + aucun +``` + +Les commandes Cargo/Tauri ne sont pas exécutables dans l’environnement d’assemblage courant (`cargo` absent). Elles restent donc explicitement `NON EXÉCUTÉES LOCALEMENT` pour ce delta ; aucune preuve opérateur antérieure n’est transformée en PASS local. + +## Validations non exécutées localement + +```text +cargo fmt --all +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test --workspace --all-targets --all-features +cargo tree --duplicates +builds Tauri +smokes live opt-in +``` + +Motif : toolchain Cargo absent du sandbox d’assemblage et aucune credential/provider live n’est injectée. Les preuves stables fournies par l’opérateur sont conservées comme contexte externe distinct ; elles ne remplacent pas les gates futurs de `0.3.10`. + +## Questions ouvertes + +Aucune question de boundary ne bloque `pre.002`. Restent volontairement à résoudre par preuve pendant les tranches prévues : + +```text +parité byte-for-byte RAW v1 des sources WS/Helius/Yellowstone full +profondeur replay réellement observable par provider au moment du smoke +nécessité éventuelle d’un profil/rôle Transport supplémentaire pour un smoke accessible +admission d’une source EARLY seulement si protocole, accès et rôle RAW sont effectivement prouvés +``` + +Ces points ne doivent pas être anticipés par des constantes, des claims lossless ou une RAW v2. + +## Non inclus + +```text +aucune nouvelle crate créée +aucun Rust modifié +aucun Transport/Config/Store code modifié +aucun kbot3 ouvert ou copié +aucun Worker live +aucun RAW v2 +aucun CHANGELOG/ROADMAP modifié +aucun prompt 0.3.11 créé +aucun Cargo gate déclaré localement +``` diff --git a/docs/plans/031-V0_3_10_RAW_TRANSACTION_INGEST_PLAN.md b/docs/plans/031-V0_3_10_RAW_TRANSACTION_INGEST_PLAN.md new file mode 100644 index 0000000..127097a --- /dev/null +++ b/docs/plans/031-V0_3_10_RAW_TRANSACTION_INGEST_PLAN.md @@ -0,0 +1,1188 @@ + + + +# Plan v0.3.10 — RAW Transaction commune + Worker d’ingestion multi-source + +## 1. But de la version + +La version `0.3.10` doit matérialiser deux responsabilités successives et indépendantes du Job historique : + +```text +1. extraire la canonicalisation RAW Transaction v1 dans ksp-raw-transaction-lib ; +2. construire ksp-worker-raw-transaction-ingest-lib comme Worker continu multi-source. +``` + +Le centre du système reste Store : + +```text +sources live + -> matériau transaction complet ou discovery/hydration + -> canonicalisation RAW v1 unique + -> RawTransaction + RawTransactionObservation + -> ksp-store-lib +``` + +Le Worker et le Job Backfill sont deux producteurs autonomes du même modèle durable. Aucun appel, lifecycle, orchestration, checkpoint ou contrat fonctionnel ne doit relier les deux. + +## 2. Base autoritaire et vérification d’ouverture + +Base fournie et vérifiée le 5 septembre 2026 : + +```text +archive KSP : khadhroony-solana-project-v0.3.9.zip +workspace.package.version avant ouverture : 0.3.9 +delta stable : deltas/0.3.9/rel.001.md +prompt : prompts/029-V0_3_10_START_PROMPT.md +``` + +Preuves d’archive : + +```text +SHA-256 = 41ef2589a11410aabfb329d387f0008e116006da60ada0802e5f72bc30d3466f +ZIP bytes = 7859118 +ZIP entries = 1855 +unzip -t = PASS +files extraits = 1674 +directories = 183 +``` + +Contrôles structurels du ZIP : + +```text +entrée absolue/traversal = 0 +symlink = 0 +.git/ = 0 +target/ = 0 +node_modules/ = 0 +Cargo.lock = 0 +.env = 0 +*.pem/*.key/*.p12/*.pfx = 0 +``` + +Le ZIP stable ne contient pas `.git`; le tag `v0.3.9` n’est donc pas réinspectable localement. L’archive est néanmoins admissible comme base fournie explicitement : version Cargo stable `0.3.9`, `CHANGELOG` ouvert sur `0.3.9`, `ROADMAP` cohérente et `deltas/0.3.9/rel.001.md` présent. + +### 2.1 Workspace réel + +Le workspace stable contient 19 membres : + +```text +ksp-app-backfill-desk +ksp-app-config-desk +ksp-app-solprices-desk +ksp-app-store-desk +ksp-app-wallet-desk +ksp-config-lib +ksp-core-lib +ksp-interface-lib +ksp-job-api +ksp-job-backfill-lib +ksp-logging-lib +ksp-offchain-transport-lib +ksp-onchain-transport-lib +ksp-program-api +ksp-store-api +ksp-store-lib +ksp-store-postgres-lib +ksp-wallet-lib +ksp-worker-api +``` + +Il ne contient encore ni `ksp-raw-transaction-lib` ni `ksp-worker-raw-transaction-ingest-lib`, ce qui correspond au point de départ attendu. + +### 2.2 Baseline statique avant modification + +Exécuté sur l’archive inchangée : + +```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 (332 table(s), 750 file(s)) +``` + +Le binaire `cargo` n’est pas présent dans l’environnement d’assemblage. Aucun `cargo fmt/check/clippy/test/tree` de cette session n’est donc déclaré PASS. Les preuves opérateur de la stable `0.3.9` sont utiles comme baseline externe mais ne sont pas requalifiées en exécution locale. + +## 3. Sources internes auditées + +Les sources obligatoires du prompt ont été relues avant décision : + +```text +RULES.md +ROADMAP.md +CHANGELOG.md +docs/000-README.md + +docs/rules/RULES_GENERAL.md +docs/rules/RULES_KSP.md +docs/rules/RULES_RUST.md +docs/rules/RULES_DEPENDENCIES.md +docs/rules/RULES_DOCUMENTATION.md +docs/rules/FILE_CONTRACTS.md +docs/rules/VERSION_WORKFLOW.md +docs/rules/PROMPT_STRUCTURE.md + +docs/architecture/002-LAYERS_AND_DEPENDENCIES.md +docs/architecture/003-COMPONENT_CONTRACTS.md +docs/architecture/004-COMPONENT_INVENTORY.md +docs/architecture/005-DEPENDENCY_GRAPH.md +docs/architecture/008-RAW_STORE_AND_REPLAY_PIPELINE.md +docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md +docs/architecture/010-APPS_SERVICES_SCENARIOS_AND_CONTROL.md +docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md + +crates/ksp-worker-api/ +docs/plans/030-V0_3_9_WORKER_API_RAW_TRANSACTION_AUDIT_PLAN.md +docs/validation/026-V0_3_9_WORKER_API_RAW_TRANSACTION_AUDIT.md + +crates/ksp-job-backfill-lib/ +docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md +docs/validation/023-V0_3_6_JOB_API_BACKFILL.md + +crates/ksp-store-api/ +crates/ksp-store-lib/ +crates/ksp-onchain-transport-lib/ +crates/ksp-config-lib/ +config/std.transport.json +config/schemas/std.transport.schema.json +config/examples/std.transport.example.json +.env.example +``` + +Le prompt `029` ne demande pas de nouvelle inspection kbot3 pour `pre.001`. L’audit fonctionnel historique est déjà consigné dans `011`; kbot3 n’est donc pas ouvert et aucune source de code kbot3 n’est utilisée. + +## 4. Décisions structurantes de `pre.001` + +Les décisions de fermeture du gate sont : + +```text +RAW v1 reste unique ; aucun RAW v2. +mainnet reste l’identité KSP canonique ; mainnet-beta reste alias externe/legacy. +ksp-raw-transaction-lib devient l’unique owner de la canonicalisation RAW v1. +La common crate dépend de Store façade, jamais de Transport/Config/Job/Worker. +RawObservationKey reste producer-owned comme le contrat Store l’indique déjà. +Le Backfill conserve son observation-key Job-owned et ses métadonnées de campagne. +Le Worker possède son runtime concret, ses source IDs, ses observation keys et sa continuité de run. +Aucun edge Job <-> Worker. +Aucun backend PostgreSQL direct. +Les sources full ne sont admises en direct que si leur projection produit le même RAW canonique. +Sinon la source devient discovery/hydration sans faux claim de complétude. +Un reconnect/resubscribe n’est jamais assimilé à un replay. +La réparation est bornée au frontier du run courant. +Les duplicates multi-source sont normaux ; les conflits de contenu sont des fautes d’intégrité. +``` + +Un point critique est ajouté au plan : la parité **byte-for-byte** entre les représentations full HTTP, WS/Helius et Yellowstone doit être prouvée avant d’autoriser une voie à persister directement. Le fait qu’un provider qualifie son message de « full » ne suffit pas à prouver l’identité canonique KSP. + +## 5. Audit exact de l’extraction `ksp-raw-transaction-lib` + +### 5.1 Contrat RAW v1 gelé + +Le canari Backfill actuel est confirmé indépendamment : + +```text +format_id = ksp.solana.raw_transaction +format_version = 1 +bytes = {"transaction":["AQID","base64"],"meta":{"a":{"x":null,"y":true},"z":1},"version":"legacy","transactionIndex":7} +byte_len = 112 +sha256 = 220792d2b15d262fda242cb220774ee9ddeffebf04dcfadabcf8ef76a9b1a7c3 +``` + +La migration vers la common crate doit conserver exactement ce vecteur et les règles déjà prouvées : + +```text +transaction binaire Base64 uniquement pour le chemin HTTP actuel +ordre top-level transaction -> meta -> version -> transactionIndex +tri récursif des clés des objets JSON meta +ordre des arrays conservé +omitted != null != value +version legacy ou entier u8 +transactionIndex u32 côté HTTP actuel +block_time hors payload RAW, converti vers RawTimestamp +signature canonique = exactement 64 octets +slot = u64 sans narrowing +SHA-256 calculé sur les bytes canoniques exacts +``` + +### 5.2 Items à déplacer et items à conserver + +| Élément actuel dans Backfill | Owner après extraction | Décision | +|:-----------------------------------------------------|:-----------------------|:----------------------------------------------------------------| +| `RAW_TRANSACTION_FORMAT_ID` | common RAW | déplacer sans changer la valeur | +| `RAW_TRANSACTION_FORMAT_VERSION` | common RAW | déplacer sans changer `1` | +| canonical JSON writer | common RAW | déplacer | +| SHA-256 du payload canonique | common RAW | déplacer | +| conversion block time -> `RawTimestamp` | common RAW | déplacer | +| décodage Base58 exact vers signature 64 bytes | common RAW | déplacer comme primitive générique | +| matériau transaction source-neutral | common RAW | créer autour des invariants RAW v1 | +| assemblage `RawTransaction` | common RAW | déplacer | +| assemblage observation depuis key + provenance sûres | common RAW | déplacer sans décider la key | +| `BackfillRawAcquisition` public | Backfill | conserver comme wrapper/compatibilité autour du résultat common | +| `BackfillHydrationOutcome` | Backfill | conserver | +| appel `get_transaction_observed` | Backfill | conserver | +| choix `Base64`, commitment et max version HTTP | Backfill/Transport | conserver hors common | +| garde request network == candidate network | Backfill | conserver | +| `BackfillSignature` admission 64..88 + scope | Backfill | conserver ; conversion exacte délègue à common | +| `job_id`, `scope_fingerprint` | Backfill | conserver | +| observation key Backfill | Backfill | conserver strictement | +| origin `Backfill` | Backfill | conserver | +| capture session `job_id` | Backfill | conserver | +| provider/endpoint observed HTTP | Backfill adapter | conserver comme entrée de provenance common | +| lifecycle/checkpoint/discovery/execution/persistence | Backfill | conserver | + +Le point `RawObservationKey` est non négociable : Store le documente déjà comme « producer-owned deterministic observation key ». La common crate ne doit donc pas inventer une clé universelle qui fusionnerait des observations de producteurs différents. + +### 5.3 Surface publique minimale cible de la common crate + +La surface à matérialiser est volontairement petite : + +```text +RAW_TRANSACTION_FORMAT_ID +RAW_TRANSACTION_FORMAT_VERSION +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_MATERIAL_INVALID +ERROR_CODE_RAW_TRANSACTION_CANONICALIZATION_INVALID +ERROR_CODE_RAW_TRANSACTION_SIGNATURE_INVALID +``` + +Sémantique : + +```text +RawTransactionMaterial + network: RawNetworkId + signature: RawTransactionSignature + slot: u64 + block_time: Option + transaction: représentation source-neutral capable de fournir le body canonique + meta: omitted/null/value + version: omitted/null/value + transaction_index: omitted/null/value + +canonicalize_raw_transaction(material) + -> RawTransaction + +assemble_raw_transaction_acquisition(transaction, observation_key, provenance) + -> vérifie que l’observation référence exactement la transaction + -> RawTransactionAcquisition { transaction, observation } +``` + +`RawTransactionWireField` est distinct du type Transport afin que common n’ait aucun edge vers Transport. Les adapters Worker/Backfill projettent explicitement les types Transport vers ce contrat. + +La représentation du body doit admettre au moins le chemin binaire canonique déjà prouvé. L’extension structurée nécessaire à Yellowstone est ajoutée uniquement avec une preuve de sérialisation/parité ; elle ne doit pas être simulée par un `serde_json::Value` opaque si cela permettrait des divergences non détectées. + +### 5.4 Dépendances exactes de la common crate + +Cible retenue : + +```text +ksp-raw-transaction-lib + -> ksp-core-lib + -> ksp-store-lib default-features=false + -> serde_json + -> sha2 +``` + +Justification : + +- `ksp-core-lib` est nécessaire aux codes/erreurs KSP propres à la canonicalisation ; +- `ksp-store-lib` fournit les reexports approuvés de `RawTransaction`, `RawPayload`, provenance et primitives ; +- `serde_json` reste requis par RAW v1 pour canonicaliser `meta` et préserver les états wire ; +- `sha2` reste requis pour le digest canonique exact. + +Interdits : + +```text +ksp-onchain-transport-lib +ksp-config-lib +ksp-job-api +ksp-job-backfill-lib +ksp-worker-api +ksp-worker-raw-transaction-ingest-lib +tokio/futures +ksp-store-postgres-lib +provider SDK +``` + +### 5.5 Erreurs et redaction + +Les erreurs common doivent être statiques et ne jamais recopier : + +```text +signature hostile +meta/payload source +transaction bytes +hash/signature dans Debug +provider URL +endpoint URL +secret/token/header +``` + +Les contextes publics admis sont uniquement des codes sûrs et bornés tels que `field`, `variant`, `actual_len`, `maximum_len` lorsque ces valeurs ne transportent aucun matériau source. + +### 5.6 Gate de parité cross-source + +Avant qu’un adapter « full » ne persiste directement : + +```text +même transaction fixture + -> HTTP getTransaction/base64 + -> WS blockSubscribe ou Helius full lorsque applicable + -> Yellowstone transaction/blocks + -> RawTransactionMaterial + -> canonicalize_raw_transaction + -> mêmes bytes + -> même content_hash +``` + +Si la parité n’est pas démontrable pour une famille, la voie reste admise comme signal de discovery et utilise hydration HTTP. Ce fallback est fonctionnellement préférable à un conflit canonique artificiel. + +La priorité `pre.001` n’est pas d’affirmer que la parité existe déjà ; elle est d’en faire un gate d’implémentation explicite. + +## 6. Audit Transport implementation-ready + +### 6.1 Matrice capabilities Worker V1 + +| Capability | Méthode / protocole | Surface KSP `0.3.9` | Gap exact | Full / hydration | Provenance disponible | Continuité / replay | Preuve accessible | Adaptation Transport | Adaptation Config | Fixture | Live smoke | +|:-------------------------------|:-----------------------------|:-------------------------------------------------|:--------------------------------------------------------------------|:----------------------------------------|:---------------------------------------------------------------------|:--------------------------------------------------------------|:----------------------------------------------------------|:-----------------------------------------|:--------------------------------------------------|:------------------------|:-----------------------------| +| HTTP transaction hydration | `getTransaction` JSON-RPC | `get_transaction_observed` | aucun gap de provenance ; projection vers common à extraire | full après réponse non-null | provider + endpoint gagnant | aucune continuité native | Mainnet/Devnet/Testnet publics | non, hors adapter common | non | oui | oui opt-in | +| HTTP live blocks | `getSlot` + `getBlock` | wrappers typés présents | `TR-B`: pas de `get_block_observed` | full par bloc | actuellement insuffisante en pool | polling depuis run frontier ; repair borné | publics | oui `get_block_observed` | rôle HTTP worker si profil dédié nécessaire | oui | oui opt-in | +| WS logs + hydration | `logsSubscribe` + HTTP | wrapper logs + sessions | composer discovery + hydration sans perdre le statut de source | hydration requise | WS session safe + HTTP observed ; Store garde endpoint full-material | resubscribe seulement, aucun replay WS | Solana public/Helius standard | adapter Worker + TR-D, pas nouveau actor | profils existants suffisants pour première preuve | oui | oui opt-in | +| WS signature + hydration | `signatureSubscribe` + HTTP | wrapper one-shot présent | utile ciblé mais pas source globale principale | hydration requise | idem | one-shot ; aucun replay | publics | aucun P0 spécifique | non | oui | secondaire | +| WS blockSubscribe | `blockSubscribe` standard | wrapper + `SolanaConfirmedBlock` | projection transactions de block vers common + parité | full si parité prouvée | session/provider logique ; pas de winner HTTP | reconnect/resubscribe, pas replay | validator public selon support ; Helius explicitement non | TR-C adapter/parité | aucune exigée si endpoint supporte | oui | opt-in, capability-dependent | +| Helius full transaction WS | `transactionSubscribe` | typed provider envelope, nested transaction JSON | transformer le nested payload en matériau common sans provider leak | full si parité prouvée, sinon hydration | provider/session/filter sûrs | reconnexion, pas historique garanti WSS | clé/tier opérateur requis selon plan | TR-C + TR-D | profil Helius éventuellement nécessaire plus tard | oui | opt-in/tier-dependent | +| Yellowstone transactions | `Subscribe.transactions` | DTO full KSP, stream/reconnect présents | projection body+meta structurés vers RAW v1 byte-identique | full si parité prouvée | provider + endpoint settings + filter + created_at disponibles | `from_slot`, replay info, reconnect snapshot | OrbitFlare Devnet / PublicNode selon accès | TR-C + TR-D + TR-E | profils V3 déjà présents | oui | oui opt-in | +| Yellowstone blocks | `Subscribe.blocks` | DTO block full + transactions | même gate de projection ; préserver slot/index/block_time | full si parité prouvée | idem | `from_slot`; upstream a corrigé replay blocks en juillet 2026 | mêmes providers | TR-C + TR-D + TR-E | non P0 | oui | oui opt-in | +| Yellowstone status + hydration | `transactions_status` + HTTP | DTO status + HTTP observed | composer signal + hydration | hydration requise | status filter/created_at + HTTP winner | replay selon provider + HTTP repair | mêmes providers | TR-D + TR-E | non P0 | oui | oui opt-in | +| Yellowstone block meta / slots | `blocks_meta`, `slots` | DTO + stream présents | aucun RawTransaction direct ; alimenter continuity tracker | non, auxiliaire | filter/slot/status/created_at | continuity evidence ; replay provider-specific | mêmes providers | TR-E côté Worker | non | oui | oui opt-in | +| EARLY source | provider/shred adapter | aucune surface générique unique | `TR-F`, uniquement protocole réellement implémenté | hydration sauf preuve meta complète | provider-specific | provider-specific | généralement payant | différé | différé | seulement si implémenté | seulement si accessible | + +### 6.2 `TR-B` — `get_block_observed` + +Statut : **confirmé P0**. + +`HttpObservedValue` existe et `get_transaction_observed` l’utilise déjà. `getBlock` doit obtenir la surface symétrique afin que le provider et l’endpoint réellement gagnants du pool soient conservés. Ne pas sélectionner un endpoint deux fois et ne pas reconstruire la provenance après coup. + +Cible : + +```text +HttpTransportPool::get_block_observed(role, slot, config) + -> Result>> +``` + +Aucun URL/header/raw body dans le résultat ou Debug. + +### 6.3 `TR-C` — projection full source-neutral + +Statut : **confirmé, mais scindé**. + +La découpe retenue évite un mauvais edge Transport -> common : + +```text +TR-C1 : common possède RawTransactionMaterial et les invariants RAW. +TR-C2 : Worker possède les adapters explicites Transport DTO -> RawTransactionMaterial. +TR-C3 : Transport n’est modifié que si un DTO actuel ne permet pas une projection fidèle/bornée. +TR-C4 : chaque adapter full doit fermer un golden de parité cross-source avant persistence directe. +``` + +Ainsi `ksp-onchain-transport-lib` ne dépend jamais de `ksp-raw-transaction-lib` et la common crate ne dépend jamais de Transport. + +### 6.4 `TR-D` — métadonnées d’acquisition live + +Statut : **confirmé, projection en deux niveaux**. + +Niveau durable Store : + +```text +provider +protocol +acquisition_method +origin = Live / Repair / Replay selon phase +received_at +observed_at si source fiable +endpoint_id logique du producteur du matériau complet +filter_id/source-id logique +capture_session_id = worker run id sûr +commitment +source payload hash/size seulement si réellement disponible et borné +``` + +Pour un chemin discovery + hydration, le provider/endpoint durable correspond au producteur du **matériau complet** (par exemple HTTP observed). `acquisition_method` et `filter_id` indiquent le chemin composite de manière sûre. La V1 ne surcharge pas un champ Store unique avec deux endpoints différents. + +Niveau runtime Worker : la source de discovery conserve sa propre santé/counters/continuity dans le snapshot concret. Une observation Store ne doit pas prétendre qu’un message logs incomplet était une transaction complète. + +### 6.5 `TR-E` — replay/from_slot + +Statut : **confirmé sans second moteur Yellowstone**. + +Le moteur KSP expose déjà `from_slot`, `SubscribeReplayInfo` et ses snapshots de reconnect. Le Worker doit seulement : + +```text +mémoriser son frontier durable par source/couverture +qualifier le replay window disponible +reconnecter avec from_slot lorsque le gap est dans la fenêtre prouvée +dédupliquer les messages replayés +réconcilier jusqu’au frontier live +refuser le claim lossless si replay/couverture n’est pas prouvé +``` + +Important : le changelog upstream du 22 juillet 2026 documente un correctif où `from_slot` avec filtre `blocks` pouvait auparavant être accepté mais livrer zéro block replay avant reprise live. Un smoke de replay **blocks** est donc obligatoire ; un smoke transactions ne couvre pas ce risque. + +### 6.6 `TR-F` — EARLY + +Statut : **réservé, non implémenté par anticipation**. + +Aucune source shred/Jetstream/preprocessed ne rentre dans le P0 si elle ne peut pas fournir les métadonnées d’exécution nécessaires au RAW canonique. Elle peut ultérieurement fournir un signal EARLY + hydration via un adapter spécialisé. + +La disparition programmée de Jito ShredStream le 5 septembre 2026 confirme qu’encoder une source vendor-specific dans la surface centrale serait une mauvaise frontière. + +## 7. Fraîcheur externe revalidée le 5 septembre 2026 + +### 7.1 Solana standard + +Les contrats utiles restent cohérents avec l’implémentation KSP : + +```text +getBlock : bloc confirmé avec transactions selon transactionDetails/encoding +blockSubscribe : méthode unstable, activation validator requise +logsSubscribe : signature + err + logs, donc hydration pour RAW complet +signatureSubscribe : ciblé/one-shot, pas une transaction full +``` + +Décision : aucun nouveau client standard ; réutiliser les wrappers actuels et fermer seulement les gaps de provenance/projection. + +### 7.2 Yellowstone upstream/proto + +`yellowstone-grpc-proto` courant est `12.7.0`, publié le 29 août 2026. Le workspace `0.3.9` déclare déjà `^12.7`; **aucun bump de dépendance n’est justifié en ouverture**. + +Le repo upstream affiche des releases Geyser 14.x plus élevées ; elles ne doivent pas être confondues avec la version de la crate proto. La compatibilité se juge sur les messages réellement consommés par KSP. + +Le changelog récent impose deux canaris : + +```text +replay blocks from_slot après correctif 2026-07-22 +Transaction V1 / champ config : proto >= 12.6 nécessaire, donc 12.7 courant est admissible +``` + +### 7.3 Provider/access matrix revalidée + +| Provider / source | État courant utile | Accès de preuve KSP | Décision `0.3.10` | +|:---------------------|:----------------------------------------------------------------------------------------------------|:-----------------------------------------------------|:-----------------------------------------------------------------------| +| Solana public RPC/WS | HTTP/WS standards accessibles ; blockSubscribe reste capability validator-dependent | sans secret, opt-in live | P0 HTTP/WS | +| PublicNode | Mainnet/Testnet RPC/WS/Yellowstone affichés ; archive access proposé, profondeur replay non prouvée | profils KSP + smokes ignored existants | P0 Yellowstone live ; replay seulement après preuve | +| OrbitFlare | Free/Developer : gRPC Devnet ; Yellowstone full fidelity ; Mainnet gRPC payant/add-on | profil Devnet + x-token operator | P0 Devnet live ; Mainnet non requis | +| Helius standard WSS | tx extension disponible ; blockSubscribe explicitement non supporté ; 10 min inactivity | dépend de clé/tier opérateur | txSubscribe adapter fixture + smoke opt-in si accès | +| Helius LaserStream | reconnect + replay jusqu’à 24 h documentés | Mainnet/tiers selon compte ; ne pas supposer gratuit | architecture compatible, live non bloquant pour release si tier absent | +| QuickNode | Yellowstone Scale+ ; port 443/x-token ; port 10000 legacy sunset 1 octobre 2026 | pas de tier gRPC actuel | bloqué tier ; aucun profil 10000 à introduire | +| Alchemy | Yellowstone Mainnet/Devnet PAYG/Enterprise | pas de tier actuel | bloqué ; replay non constant | +| Jito ShredStream | shutdown annoncé pour le 5 septembre 2026, migration DoubleZero recommandée | aucun besoin | `SUNSET`, ne pas implémenter TR-F dessus | +| EARLY autres | protocoles/prix variables | variable | adapter seulement après protocole+accès+RAW role prouvés | + +Alchemy reste volontairement `À REVALIDER` sur la profondeur replay : sa page dédiée Historical Replay annonce environ `432000` slots / `48 h`, tandis que son overview/SubscribeRequest mentionne encore `6000` slots. KSP ne doit encoder **aucune** constante Alchemy ; le runtime se fie à une capability/replay info observée ou à un paramètre configuré/prouvé. + +## 8. Surface publique minimale du Worker concret + +La V1 cible la surface suivante, sans paramètre historique métier : + +```text +RAW_TRANSACTION_INGEST_WORKER_KIND_CODE + +RawTransactionIngestSettings +RawTransactionSourceId +RawTransactionSourceSettings +RawTransactionSourceCapability +RawTransactionSourceRole + +RawTransactionIngestWorker +RawTransactionIngestHandle +RawTransactionIngestSnapshot +RawTransactionIngestSnapshotSource +RawTransactionSourceSnapshot +RawTransactionContinuityState + +ERROR_CODE_RAW_TRANSACTION_INGEST_SETTINGS_INVALID +ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID +ERROR_CODE_RAW_TRANSACTION_INGEST_SOURCE_FAILED +ERROR_CODE_RAW_TRANSACTION_INGEST_CONTINUITY_LOST +ERROR_CODE_RAW_TRANSACTION_INGEST_CONTENT_CONFLICT +``` + +Le start reçoit uniquement des réglages techniques et ressources préparées : + +```text +network +worker identity +liste de sources activées +safe source/role/filter ids +priorités / required-vs-optional +bounds techniques queues/concurrency/poll/retry +Transport runtime/settings déjà résolus +Store façade déjà ouverte/cohérente réseau +``` + +Interdit au start : + +```text +signature +program_id +address +before/after +slot range historique +historical limit +BackfillRequest +BackfillCheckpoint +JobId +``` + +## 9. Ownership runtime et supervision + +### 9.1 Executor et tâches + +Décision : le caller fournit un runtime Tokio actif ; le Worker **n’instancie pas son propre runtime**. Le Worker possède les tâches qu’il spawn sur cet executor et ne rend jamais leurs `JoinHandle` publics. + +Schéma : + +```text +start + -> lifecycle Starting + -> supervisor task + -> source tasks N + -> central admission/persistence task + -> continuity/repair coordination + -> latest-value publisher + -> lifecycle Running +``` + +`RawTransactionIngestHandle` expose seulement : + +```text +request_stop() +snapshot_source() +worker_snapshot_source()/projection commune +wait_terminal() ou équivalent borné par le caller +``` + +La surface exacte de wait doit rester async et ne pas exposer Tokio nominalement si une future abstraction simple suffit ; l’implémentation privée peut utiliser Tokio. + +### 9.2 Start/stop + +Séquence normale : + +```text +Created -> Starting -> Running -> Stopping -> Stopped +``` + +Fault : + +```text +Starting/Running/Stopping -> Faulted(static ErrorCode) +``` + +Stop : + +```text +request_stop idempotent +stop admissions nouvelles +signaler source tasks +half-close/close streams avec les primitives Transport existantes +drainer seulement le travail déjà admis dans une borne explicite +persister les dernières acquisitions admises +publier snapshot terminal +terminer supervisor +``` + +Aucune source ne doit survivre à la terminaison du Worker. + +### 9.3 Source supervisor + +Une source possède au minimum : + +```text +source_id sûr +capability +role alternative/complementary/redundant/specialized +required/optional +priority +health +activity +continuity class +counters +retry/reconnect state borné +``` + +Le supervisor isole une source défaillante sans arrêter automatiquement les sources saines. Il recalcule `WorkerHealth` : + +```text +Healthy = toutes les garanties requises sont satisfaites +Degraded = au moins une source/garantie optionnelle ou réparable est dégradée +Unhealthy = garantie requise non satisfaite mais policy de recovery encore active +Faulted = décision terminale après budget/policy ou conflit d’intégrité +``` + +## 10. Multi-source concurrency et backpressure + +### 10.1 Pipeline interne + +```text +source task + -> bounded acquisition channel + -> classify full / discovery / continuity + -> normalize or hydrate + -> canonicalize common RAW + -> Store atomic acquisition + -> update durable frontier/counters + -> latest-value snapshot +``` + +Aucune queue unbounded. + +Les bornes doivent être worker-owned et validées, avec defaults conservateurs et maximums publics seulement lorsqu’ils constituent une vraie limite de sécurité. Une saturation de queue n’est jamais un drop silencieux : + +```text +si upstream peut backpressure -> attendre dans deadline bornée +sinon -> marquer gap/saturation -> lancer repair si possible +si repair impossible et garantie requise -> Degraded/Unhealthy puis Faulted selon policy +``` + +### 10.2 Admission et dedup + +Identité de convergence : + +```text +(network, signature) +``` + +Règles : + +```text +une acquisition full par source produit son observation propre +le Store décide entity new/idempotent/content-conflict +une observation identique est idempotente via sa producer-owned key +une observation d’une autre source ne doit pas être supprimée parce que l’entité existe déjà +un signal discovery incomplet ne devient pas une RawTransactionObservation mensongère +les hydrations duplicate d’une même signature peuvent être coalescées en mémoire pour réduire l’I/O, +mais uniquement si la provenance durable du matériau complet reste exacte +``` + +Le cache de coalescence est borné et optimisation-only. La correction reste garantie par Store. + +### 10.3 Content conflict + +`même (network, signature) + payload canonique divergent` est une faute d’intégrité, pas une concurrence normale. + +Policy V1 : + +```text +arrêter les nouvelles admissions +conserver le code statique de conflit +ne pas choisir un provider gagnant +ne pas réécrire l’entité +publier Faulted(ERROR_CODE_RAW_TRANSACTION_INGEST_CONTENT_CONFLICT) +``` + +Le payload/signature/hash divergent ne doit pas apparaître dans logs/snapshots publics. + +## 11. Continuité et gap repair + +### 11.1 Frontier de run + +Le Worker fixe au démarrage un `run_start_frontier`. Il ne répare jamais arbitrairement avant cette borne à la demande d’un caller. + +La continuité est suivie **par source et par classe de couverture**, car toutes les sources ne prouvent pas la même chose : + +```text +block-complete coverage +filtered transaction coverage +signal/discovery coverage +best-effort live coverage +``` + +Un simple `last_seen_slot` ne prouve pas l’absence de transactions manquantes. + +### 11.2 Ordre de repair + +Pour un gap né pendant le run : + +```text +1. replay natif adressable qualifié (Yellowstone from_slot) +2. source redondante dont la couverture prouve la plage +3. scan HTTP des slots/blocs manquants +4. hydration HTTP des signatures découvertes +5. gap explicite non résolu si aucune preuve suffisante +``` + +Le Worker reprend un statut Healthy seulement lorsque la preuve de couverture attendue est rétablie. + +### 11.3 Bornes + +Le runtime doit imposer : + +```text +nombre maximal de gaps ouverts +largeur maximale d’un repair HTTP par incident +concurrency de repair +retry/backoff max +replay start >= run_start_frontier sauf bootstrap technique immédiat décidé au start +pas de boucle infinie autour d’un slot indisponible +``` + +Une fenêtre replay provider est une donnée de capability, pas une constante provider hardcodée dans le Worker. + +### 11.4 Reconnect ≠ replay + +```text +WS reconnect + resubscribe + -> connexion rétablie + -> continuity UNKNOWN jusqu’à preuve/repair + +Yellowstone reconnect avec from_slot prouvé + -> replay demandé + -> continuity REPAIRING + -> continuity PROVEN seulement après rattrapage/validation +``` + +## 12. Snapshots et notifications concrètes + +`ksp-worker-api` reste inchangé. Le Worker concret publie deux projections latest-value : + +```text +WorkerSnapshot commun +RawTransactionIngestSnapshot concret +``` + +Le snapshot concret minimal contient uniquement des données sûres : + +```text +worker id/kind/state/health/activity/sequence +run start frontier +last durable frontier global lorsqu’il est significatif +source count +healthy/degraded/unhealthy/failed source counts +received signal count +full material count +hydration requested/completed/missing counts +entity new/idempotent counts +observation new/idempotent counts +content conflict count +gaps detected/repaired/unresolved counts +repair active bool/count +per-source: source_id, capability code, health, activity, continuity state, safe counters, slots/frontiers +``` + +Pas de : + +```text +signature +transaction bytes/meta/logs +endpoint URL +API key/token/header +raw remote error text +provider payload +filter/account values sensibles +``` + +Pour les rates, la V1 publie des compteurs monotones et des timestamps/sequence sûrs suffisants pour calculer des rates sans introduire de float métier ni event bus. Un rate pré-calculé n’entre dans l’API que si une mesure concrète l’exige pendant l’implémentation. + +Le publisher est latest-value/coalescent : lecteur lent ou absent n’influence jamais le lifecycle. + +## 13. Décision Config/composition + +### 13.1 Aucun edge Worker -> Config + +La décision du prompt est conservée : + +```text +ksp-worker-raw-transaction-ingest-lib -X-> ksp-config-lib +``` + +Le Worker reçoit des settings source-neutral validés et des ressources Transport/Store préparées. + +### 13.2 Pas de nouveau document métier Worker en `pre.001` + +`std.transport` V3 possède déjà : + +```text +network/cluster +endpoint id +provider +HTTP roles + priority + limits +WS protocol kind + session settings +gRPC protocol + metadata publique/secrète + session settings +``` + +Cela suffit pour matérialiser et tester la bibliothèque Worker programmatiquement. `0.3.10` n’ajoute pas par défaut un `std.raw_transaction_ingest` qui forcerait `ksp-config-lib` à dépendre du Worker concret. + +Le choix utilisateur/composition de « quelles sources activer » appartient naturellement au futur `ksp-app-raw-transaction-ingest-desk` `0.3.11`. Si `0.3.10` découvre un manque **Transport** indispensable (par exemple un profil Helius de preuve ou un rôle HTTP live), l’adaptation Config reste limitée au standard Transport et ne crée pas de dépendance inversée. + +### 13.3 Secrets + +```text +Config résout les secrets +Transport settings les reçoivent sous wrappers redacted +Worker ne lit jamais std::env/.env +Worker ne logge jamais endpoint/token/header +source snapshot n’expose que source_id/capability/health +``` + +`KSP_SECRET_HELIUS_API_KEY` reste l’unique secret Helius lorsqu’un profil Helius est ajouté ; ne pas multiplier des secrets par méthode. + +## 14. Threat model `0.3.10` + +| Risque | Impact | Garde prévue | +|:--------------------------------------------|:------------------------------------|:------------------------------------------------------------------------------| +| divergence RAW entre sources | corruption logique / conflict flood | parity golden cross-source avant direct persist ; conflict terminal explicite | +| provider payload hostile/oversized | mémoire/CPU | bornes Transport existantes + material/common bounds | +| queue saturation | perte silencieuse | aucun drop silencieux ; gap + repair/degraded | +| source lente bloquant toutes les autres | arrêt global | source tasks indépendantes + bounded central admission | +| duplicate storm replay/multi-source | I/O/CPU | Store idempotence + cache de coalescence borné | +| replay trop ancien | faux lossless | replay info/capability + run frontier + fallback HTTP ou gap explicite | +| reconnect pris pour continuity | données manquantes | états distincts reconnect/resubscribe/replay/repair | +| full provider incomplet | RAW invalide | completeness/parity gate ; hydration fallback | +| content conflict | first-provider-wins | terminal conflict, aucune overwrite | +| Store indisponible | backlog infini | pause/admission bornée + retry budget + fault | +| source endpoint/secret dans Debug | fuite | wrappers redacted + security tests + static scans | +| observation key collision inter-producteurs | perte de provenance | key producer-owned avec domaine Worker distinct du Backfill | +| Job semantics dans Worker | couplage architectural | tests de dependency/public surface ; aucun request historique | +| Worker semantics dans common | cycle/couplage | common sans Worker/Job/runtime | +| provider-specific enum fermé | dette extension | capability-oriented settings ; provider reste metadata Transport | +| transaction V1 protobuf perdu | faux canonical | proto 12.7 courant + fixture V1 + parity | +| Yellowstone block replay regression | gap silencieux | smoke block replay dédié après fix upstream | +| alias `mainnet-beta` réintroduit | split identity Store | mainnet canonique aux frontières KSP ; alias seulement adapter externe | + +## 15. Stratégie de preuves + +### 15.1 Tests déterministes + +Common : + +```text +golden RAW v1 exact bytes/hash existant +omitted/null/value meta/version/index +canonical JSON object ordering +arrays ordering +string escaping/numbers +block time negative/overflow/max +signature Base58 malformed/length/64-byte exact +payload max bounds +Debug/error redaction +external consumer crate-root only +manifest/dependency boundary +``` + +Transport/adapters : + +```text +get_block_observed winner provenance +HTTP block -> material +WS block -> material +Helius full -> material +Yellowstone transaction -> material +Yellowstone block -> N materials +status/logs -> hydration candidate only +Transaction V1 config fixture +cross-source parity golden +``` + +Worker : + +```text +start/stop state machine +multi-source concurrency +slow/failing source isolation +bounded channel saturation +dedup/coalescence +multiple observations same entity +content conflict terminal path +Store retry/failure path +gap detection +native replay state +redundant-source repair +HTTP block repair +unresolved gap degraded/fault policy +shutdown drain bound +latest-value slow/late listeners +snapshot redaction +no historical start parameters +``` + +### 15.2 Integration locale + +Prévoir des fake sources/fixtures sans réseau pour prouver : + +```text +source -> common -> Store façade fake +multi-source same entity + distinct observations +conflicting entity +out-of-order slots +replay duplicates +repair succeeds/fails +stop while source/hydration/store future pending +``` + +Aucun PostgreSQL physique requis pour ces tests unitaires/integration de bibliothèque. + +### 15.3 Store persistence proof + +Le gate final doit inclure au moins un smoke opt-in sur un Store réel disponible : + +```text +une transaction nouvelle +réacquisition idempotente +observation additionnelle autre source +content conflict explicitement rejeté +shutdown propre +``` + +Le Worker dépend uniquement de `ksp-store-lib` ; le test live peut activer le backend via feature/composition supérieure. + +### 15.4 Smokes live accessibles + +Priorité : + +```text +Solana public Devnet HTTP getTransaction/getBlock +Solana public Devnet WS logs +PublicNode Mainnet/Testnet Yellowstone si credentials KSP disponibles +OrbitFlare Devnet Yellowstone avec licence x-token opérateur +Helius standard/transactionSubscribe uniquement si clé+tier disponibles +``` + +Tous les tests réseau, secrets ou tiers sont opt-in/ignored. + +### 15.5 Replay/continuity proofs + +Séparer obligatoirement : + +```text +Yellowstone transaction replay from_slot +Yellowstone block replay from_slot +replay duplicate dedup +replay out-of-window failure +reconnect sans replay -> continuity unknown/degraded +HTTP repair d’un gap de run contrôlé +``` + +Une preuve sur `transactions` ne valide pas automatiquement `blocks`. + +## 16. Graphe de dépendances cible + +```text +ksp-core-lib + ^ + | +ksp-store-api <- ksp-store-lib <- ksp-raw-transaction-lib + ^ ^ + | | + | +-------+------------------+ + | | | + | ksp-job-backfill-lib ksp-worker-raw-transaction-ingest-lib + | ^ ^ + | | | + +----------+--------------------------+ + | + ksp-onchain-transport-lib + +ksp-worker-api --------------------------> ksp-worker-raw-transaction-ingest-lib +ksp-logging-lib -------------------------> ksp-worker-raw-transaction-ingest-lib +``` + +Lecture des flèches du schéma : les consumers dépendent des lower layers ; aucun lower layer ne dépend d’un consumer. Le dessin ne crée pas d’edge `ksp-store-lib -> common` : c’est bien `common -> ksp-store-lib`. + +Edges exacts attendus : + +```text +ksp-raw-transaction-lib + -> ksp-core-lib + -> ksp-store-lib default-features=false + -> serde_json + -> sha2 + +ksp-job-backfill-lib + -> ksp-raw-transaction-lib + -> ksp-job-api + -> ksp-onchain-transport-lib + -> ksp-store-lib default-features=false + -> dépendances runtime existantes + +ksp-worker-raw-transaction-ingest-lib + -> ksp-worker-api + -> ksp-onchain-transport-lib + -> ksp-raw-transaction-lib + -> ksp-store-lib default-features=false + -> ksp-logging-lib + -> tokio/futures uniquement si l’implémentation concrète les exige +``` + +`ksp-interface-lib` reste absent sauf nécessité passive démontrée. + +## 17. Sizing et trajectoire recalibrée + +La prévision initiale du prompt est trop dense pour certaines tranches si chacune doit rester autour de 15–20 minutes effectives. Le plan retenu sépare canonicalisation, parité, runtime et sources : + +### `pre.001` — audit/sizing/plan + +Présente tranche : archive/règles, common extraction, capability matrix, fraîcheur, runtime, continuity, threat model, preuves et graphe. Aucune implémentation lourde. + +### `pre.002` — common RAW foundation + +Créer `ksp-raw-transaction-lib`, types source-neutral minimaux, signature parser, canonical JSON, SHA-256 et golden RAW v1 exact. Aucun Worker. + +### `pre.003` — migration Backfill vers common + +Remplacer la canonicalisation privée du Backfill par common, conserver son observation key/provenance/campagne et prouver zéro changement bytes/hash/comportement de campagne. + +### `pre.004` — HTTP observed block + block material + +Ajouter `get_block_observed`, fixtures provenance, extraction transaction par transaction et adapters HTTP block vers matériau common. Aucun Worker live complet encore. + +### `pre.005` — parité WS/Helius full + +Fermer projection `blockSubscribe` + Helius `transactionSubscribe` vers matériau common, golden parity ou fallback hydration explicitement qualifié. + +### `pre.006` — parité Yellowstone transactions/blocks + +Fermer les adapters structurés Yellowstone transaction/block, Transaction V1, meta et cross-source parity. Aucune persistance directe si le gate byte-identical échoue. + +### `pre.007` — Worker foundation/runtime + +Créer la crate Worker concrète, settings, handle, lifecycle, supervisor, source abstraction interne, bounded channel, common/concrete snapshots et shutdown sans source live complexe. + +### `pre.008` — Yellowstone live + continuity + +Brancher transactions/blocks/status, source health, from_slot/replay info, run frontier et tests déterministes de replay/duplicates. + +### `pre.009` — WS/HTTP live + +Brancher logs+hydration, blockSubscribe, HTTP live block polling/hydration et Helius transactionSubscribe selon capability/access. + +### `pre.010` — multi-source persistence/dedup/hardening + +Convergence Store, observations multiples, content conflicts, coalescence bornée, backpressure, source failure isolation et adversarial tests. + +### `pre.011` — gap repair complet + +Replay natif, redondance, HTTP block scan, hydration, unresolved gaps, policy degraded/unhealthy/faulted et shutdown pendant repair. + +### `pre.012` — Config/profiles + provider smokes accessibles + +Ajouter seulement les profils/roles Transport réellement nécessaires, exécuter les smokes gratuits/credentials disponibles et documenter clairement les tiers bloqués. Pas d’edge Worker -> Config. + +### `pre.013` — EARLY si prouvé, sinon consolidation + +N’ajouter un adapter EARLY que si protocole, accès et rôle RAW sont prouvés. Sinon consacrer la tranche aux dettes/hardening découvertes ; ne pas créer de faux support. + +### `pre.014` — gate technique/live final + +Workspace complet, all-targets/all-features, cargo trees, duplicate tree, smokes pertinents, continuity repair et Store proof. + +### `pre.015` — réconciliation documentaire finale + +README/USAGE/architecture/plan/validation uniquement ; aucun rattrapage fonctionnel. + +### `pre.016` — préparation de publication + +Prompt `0.3.11`, CHANGELOG, ROADMAP et fichiers mécaniques de version/delta uniquement. + +### `rel.001` — publication stable + +Publication mécanique `v0.3.10` sans rattrapage code/doc. + +Cette trajectoire reste souple : une tranche réellement petite peut être fusionnée, mais aucune tranche > environ 20 minutes ne doit être artificiellement conservée monolithique. + +## 18. Gates Cargo futurs obligatoires + +Dès création des nouvelles crates et à la fermeture technique : + +```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 --workspace --all-targets --all-features +cargo tree -p ksp-raw-transaction-lib --edges normal +cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal +cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features +cargo tree --duplicates +``` + +Les smokes live restent séparés et opt-in. + +## 19. Critères de sortie `pre.001` + +| Critère du prompt | Fermeture | +|:------------------------------------------|:--------------------------------------------------------------| +| boundary exacte common crate | définie sections 5.2–5.5 | +| migration Backfill sans changement RAW v1 | golden + ownership décidés sections 5.1–5.3 | +| surface publique Worker concrète | définie section 8 | +| runtime/source supervision | définis sections 9–10 | +| capability matrix implementation-ready | section 6.1 | +| TR-B..TR-F réévalués | sections 6.2–6.6 | +| Config/source settings sans secret leak | section 13 | +| continuity/gap repair bornés | section 11 | +| snapshot concret | section 12 | +| multi-source dedup/provenance/persistence | section 10 | +| provider/access/proof matrix | section 7 | +| tests/smokes | section 15 | +| dependency graph | section 16 | +| forecast détaillé dimensionné | section 17 | +| aucune implémentation lourde avant plan | respecté : seulement docs + version prerelease dans `pre.001` | + +## 20. Hors périmètre confirmé + +```text +ksp-app-raw-transaction-ingest-desk # 0.3.11 +nouvelles stratégies historiques Backfill # 0.3.12 +paramètres métier historiques dans Worker +Backfill checkpoint dans Worker +RawAccountState ingest worker +Program/DEX/materialization +backend PostgreSQL direct +provider SDK +control plane global +RAW v2 +source Jito ShredStream sunset +``` + +## 21. Sources externes de fraîcheur + +Consultées le 5 septembre 2026 uniquement pour les faits pouvant changer et influer sur l’implémentation : + +```text +https://solana.com/docs/rpc/http/getblock +https://solana.com/docs/rpc/websocket/blocksubscribe +https://solana.com/docs/rpc/websocket/logssubscribe +https://solana.com/docs/rpc/websocket/signaturesubscribe + +https://docs.rs/crate/yellowstone-grpc-proto/latest +https://github.com/rpcpool/yellowstone-grpc/blob/master/CHANGELOG.md +https://github.com/rpcpool/yellowstone-grpc/blob/master/yellowstone-grpc-proto/proto/geyser.proto + +https://www.helius.dev/docs/api-reference/rpc/websocket/transactionsubscribe +https://www.helius.dev/docs/api-reference/rpc/websocket/blocksubscribe +https://www.helius.dev/laserstream + +https://solana-yellowstone-grpc.publicnode.com/ +https://orbitflare.com/pricing +https://docs.orbitflare.com/data-streaming/yellowstone + +https://www.quicknode.com/docs/solana/solana-grpc/overview +https://www.alchemy.com/docs/reference/yellowstone-grpc-overview +https://www.alchemy.com/docs/reference/yellowstone-grpc-historical-replay + +https://docs.jito.wtf/lowlatencytxnfeed/ +``` + +Les prix, tiers, profondeurs de replay et disponibilités provider restent des données d’audit datées, jamais des constantes métier du Worker. diff --git a/docs/validation/027-V0_3_10_RAW_TRANSACTION_INGEST.md b/docs/validation/027-V0_3_10_RAW_TRANSACTION_INGEST.md new file mode 100644 index 0000000..5f88404 --- /dev/null +++ b/docs/validation/027-V0_3_10_RAW_TRANSACTION_INGEST.md @@ -0,0 +1,354 @@ + + + +# Validation v0.3.10 — RAW Transaction commune + Worker d’ingestion + +## 1. Rôle du document + +Ce document suit les preuves de la release `0.3.10` : extraction de la canonicalisation RAW v1 vers `ksp-raw-transaction-lib`, migration Backfill puis matérialisation du Worker continu multi-source `ksp-worker-raw-transaction-ingest-lib`. + +Il distingue toujours : + +```text +preuve exécutée +preuve seulement planifiée +preuve live accessible +preuve live bloquée par secret/tier +non-claim explicite +``` + +## 2. Gate `pre.001` — audit/sizing/plan + +État : **fermé pour la planification**, sans claim Cargo local. + +### 2.1 Base contrôlée + +```text +archive : khadhroony-solana-project-v0.3.9.zip +SHA-256 : 41ef2589a11410aabfb329d387f0008e116006da60ada0802e5f72bc30d3466f +bytes : 7859118 +entries : 1855 +unzip -t : PASS +workspace members : 19 +workspace.package.version base : 0.3.9 +stable delta : deltas/0.3.9/rel.001.md +``` + +Sécurité archive : + +```text +absolute/traversal entries : 0 +symlinks : 0 +.git/ : 0 +target/ : 0 +node_modules/ : 0 +Cargo.lock : 0 +.env : 0 +private-key-like files checked : 0 +``` + +Le ZIP ne contient pas `.git`; le tag n’est donc pas directement inspectable dans cet environnement. + +### 2.2 Baseline statique exécutée avant modification + +```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 (332 table(s), 750 file(s)) +``` + +### 2.3 Cargo local + +```text +cargo : indisponible dans l’environnement d’assemblage +``` + +Par conséquent : + +```text +cargo fmt : NON EXÉCUTÉ ici +cargo check : NON EXÉCUTÉ ici +cargo clippy: NON EXÉCUTÉ ici +cargo test : NON EXÉCUTÉ ici +cargo tree : NON EXÉCUTÉ ici +Tauri build : NON EXÉCUTÉ ici +``` + +Aucun de ces gates n’est déclaré PASS par cette session. Le journal opérateur fourni pour la stable `0.3.9` montre un gate complet antérieur ; il reste une preuve externe de la base stable, pas une exécution `pre.001` locale. + +## 3. Preuves de conception fermées en `pre.001` + +### 3.1 Common RAW + +Décisions prouvées par inspection du code courant : + +```text +format_id courant = ksp.solana.raw_transaction +format_version courant = 1 +RawObservationKey est explicitement producer-owned dans Store +RawTransaction identity = network + signature +RawTransactionObservation est séparée de l’entité +ksp-store-lib reexporte les primitives nécessaires +Backfill conversion mélange actuellement canonicalisation commune et metadata Job-owned +``` + +Canari RAW v1 recalculé : + +```text +bytes = {"transaction":["AQID","base64"],"meta":{"a":{"x":null,"y":true},"z":1},"version":"legacy","transactionIndex":7} +len = 112 +sha256 = 220792d2b15d262fda242cb220774ee9ddeffebf04dcfadabcf8ef76a9b1a7c3 +``` + +Le plan interdit tout déplacement de `job_id`, `scope_fingerprint`, lifecycle, checkpoint ou observation-key algorithm dans common. + +### 3.2 Transport + +Inventaire confirmé dans `ksp-onchain-transport-lib` : + +```text +HttpObservedValue +get_transaction_observed +get_block / get_blocks / get_blocks_with_limit +logsSubscribe +signatureSubscribe +blockSubscribe +Helius transactionSubscribe +Yellowstone transactions +Yellowstone transactions_status +Yellowstone blocks +Yellowstone blocks_meta +Yellowstone slots +Yellowstone from_slot +SubscribeReplayInfo / reconnect snapshot +``` + +Gaps requalifiés : + +```text +TR-B confirmé : get_block_observed +TR-C confirmé/scindé : common material + adapters Worker + Transport seulement si DTO insuffisant +TR-D confirmé : provenance durable full-material + runtime source projection +TR-E confirmé : réutiliser from_slot/replay existant, aucun second moteur +TR-F réservé : aucun EARLY sans protocole+accès+rôle RAW prouvés +``` + +### 3.3 Config + +Constats : + +```text +std.transport format_version = 3 +mainnet logique déjà canonique +profils OrbitFlare Devnet et PublicNode Mainnet/Testnet déjà présents +gRPC metadata publique/secrète déjà typée et redacted +HTTP roles/priorities/limits déjà supportés +WS protocol/session déjà supportés +``` + +Décision : pas d’edge Worker -> Config et pas de nouveau document métier Worker imposé dans `0.3.10`. Une adaptation Config n’est admise que pour un manque Transport concret découvert pendant l’implémentation. + +## 4. Fraîcheur externe `pre.001` + +### 4.1 Yellowstone + +Vérifié le 5 septembre 2026 : + +```text +yellowstone-grpc-proto latest = 12.7.0 +publication = 2026-08-29 +workspace KSP = ^12.7 +``` + +Décision : aucun bump en ouverture. + +Canaris imposés par changements upstream récents : + +```text +Transaction V1/config doit survivre à la projection +block replay from_slot doit avoir un smoke dédié +``` + +### 4.2 Providers + +| Source | Fait revalidé | Type de preuve `0.3.10` | +|:-----------------|:-------------------------------------------------------------------------------------|:---------------------------------------| +| Solana public | HTTP/WS standard accessibles ; blockSubscribe unstable | live opt-in + fixtures | +| PublicNode | Yellowstone Mainnet/Testnet affiché ; archive access proposé | live opt-in si token/config disponible | +| OrbitFlare | Devnet gRPC Free/Developer ; Yellowstone full-fidelity | live opt-in avec x-token opérateur | +| Helius | transactionSubscribe courant ; blockSubscribe non supporté ; LaserStream replay 24 h | fixture + live si tier/key | +| QuickNode | gRPC Scale+ ; port 443/x-token ; 10000 sunset 2026-10-01 | tier-bloqué | +| Alchemy | PAYG/Enterprise ; docs replay 6000 vs 432000 slots contradictoires | tier-bloqué, aucune constante | +| Jito ShredStream | shutdown annoncé 2026-09-05 | exclu TR-F | + +## 5. Gates de parité RAW obligatoires + +Une source dite full n’obtient le statut `direct canonical producer` qu’après : + +```text +same fixture identity +same canonical bytes +same SHA-256 +same slot +same block_time semantics +same version/index semantics +``` + +Familles à prouver séparément : + +```text +HTTP getTransaction +HTTP getBlock transaction +WS blockSubscribe transaction +Helius transactionSubscribe full +Yellowstone transaction +Yellowstone block transaction +Transaction V1 +``` + +En cas d’échec de parité : + +```text +pas de RAW v2 automatique +pas de first-provider-wins +pas de content normalization ad hoc non documentée +source utilisée comme discovery + hydration HTTP jusqu’à résolution +``` + +## 6. Gates Worker à fermer pendant la release + +### 6.1 Lifecycle/runtime + +```text +Created -> Starting -> Running -> Stopping -> Stopped +Faulted terminal +stop idempotent +caller-owned Tokio runtime +Worker-owned spawned tasks +aucun JoinHandle public +shutdown borné +aucune tâche source survivante +``` + +### 6.2 Sources et backpressure + +```text +N sources simultanées +bounded channels seulement +slow source isolation +queue saturation observable +aucun drop silencieux +degraded/unhealthy/fault policy explicite +``` + +### 6.3 Persistence + +```text +new entity + new observation +idempotent entity + new source observation +idempotent observation +content conflict terminal +aucun backend physique dans Worker +``` + +### 6.4 Continuité + +```text +run frontier borné +reconnect != replay +transaction replay from_slot +block replay from_slot +redundant-source repair +HTTP block repair +hydration repair +unresolved gap reste visible +aucun historical caller parameter +``` + +### 6.5 Observabilité + +```text +WorkerSnapshot commun +RawTransactionIngestSnapshot concret +latest-value indépendamment des lecteurs +source health/counters/gaps/frontiers sûrs +aucun payload/signature/URL/secret +``` + +## 7. Matrice de types de preuve + +| Preuve | Déterministe | Réseau externe | Secret/tier | Gate release | +|:------------------------------|:------------:|:--------------:|:---------------:|:--------------------------------------------------| +| common golden RAW v1 | oui | non | non | obligatoire | +| cross-source parity fixtures | oui | non | non | obligatoire | +| Worker fake multi-source | oui | non | non | obligatoire | +| Store façade fake | oui | non | non | obligatoire | +| HTTP/WS Solana public smoke | non | oui | non | opt-in, pertinent | +| PublicNode Yellowstone | non | oui | possible | opt-in si accès | +| OrbitFlare Devnet Yellowstone | non | oui | x-token | opt-in si accès | +| Helius transactionSubscribe | non | oui | key/tier | opt-in, non bloquant si tier absent | +| QuickNode Yellowstone | non | oui | tier | bloqué, fixture suffit | +| Alchemy Yellowstone | non | oui | PAYG/Enterprise | bloqué, fixture suffit | +| PostgreSQL Store proof | non | local/externe | URI dédiée | opt-in gate technique si environnement disponible | + +## 8. Commands de gate cible + +À exécuter dès que Rust est modifié puis au gate technique final : + +```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 --workspace --all-targets --all-features +cargo tree -p ksp-raw-transaction-lib --edges normal +cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal +cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features +cargo tree --duplicates +``` + +Ne jamais remplacer un gate non exécuté par un ancien log stable. + +## 9. Non-claims `pre.001` + +À ce stade il n’est **pas** affirmé que : + +```text +Yellowstone full produit déjà des bytes RAW v1 identiques à HTTP +Helius full produit déjà des bytes RAW v1 identiques à HTTP +PublicNode/OrbitFlare replay est disponible à une profondeur donnée +Alchemy a une profondeur replay stable +une source WS reconnectée est lossless +une source EARLY est implémentée +le Worker concret existe déjà +la common crate existe déjà +un test Cargo de pre.001 a été exécuté localement +``` + +Ces points deviennent des gates ou restent explicitement bloqués. + +## 10. Trajectoire de validation + +```text +pre.002 common golden + dependency firewall +pre.003 Backfill migration parity +pre.004 observed block +pre.005 WS/Helius parity +pre.006 Yellowstone parity +pre.007 Worker runtime foundation +pre.008 Yellowstone live/replay +pre.009 WS/HTTP live +pre.010 multi-source Store/hardening +pre.011 gap repair +pre.012 Config/profiles + provider smokes +pre.013 EARLY ou consolidation +pre.014 final technical/live gate +pre.015 final docs reconciliation +pre.016 publication preparation +rel.001 stable publication +```