From 79e278064d976706edb9cd1ca41c04a1a58a6fe0 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Wed, 9 Sep 2026 23:24:20 +0200 Subject: [PATCH] v0.3.12-pre.012 --- Cargo.toml | 4 +- README.md | 4 +- .../README.md | 206 +++++++++++------- .../USAGE.md | 187 +++++++++++----- deltas/0.3.12/pre.012.md | 71 ++++++ docs/architecture/004-COMPONENT_INVENTORY.md | 4 +- docs/architecture/005-DEPENDENCY_GRAPH.md | 9 +- .../009-ACQUISITION_WORKERS_AND_JOBS.md | 15 +- .../011-RAW_TRANSACTION_ACQUISITION.md | 93 ++++---- ...0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md | 93 +++++++- 10 files changed, 493 insertions(+), 193 deletions(-) create mode 100644 deltas/0.3.12/pre.012.md diff --git a/Cargo.toml b/Cargo.toml index f7bf7c6..3225680 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 536 +# version: 537 [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-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"] [workspace.package] -version = "0.3.12-pre.11" +version = "0.3.12-pre.12" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/README.md b/README.md index 8729c59..94f8218 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ - + # Khadhroony Solana Project @@ -57,7 +57,7 @@ La couche RAW dispose d'une façade Store backend-neutral et d'un premier job hi `ksp-worker-api` fournit désormais la fondation générique des services continus : identité Worker, lifecycle borné, health/activity, intention de stop coopératif et observation latest-value. Cette API reste Core-only, runtime-neutral et sans connaissance Solana, Transport, Store ou Job. Elle ne démarre ni n'arrête elle-même un runtime concret. -`ksp-worker-raw-transaction-ingest-lib` est désormais le premier Worker concret distinct du Job Backfill. Sa fondation source-neutral possède le lifecycle Start/Stop, l'admission bornée, la canonicalisation Common RAW, la persistance Store backend-neutral, le shutdown borné et les snapshots latest-value, mais aucune source réseau productive ni dépendance Transport. Les adapters live/catch-up seront ajoutés dans les tranches suivantes sans transformer le Worker en campagne historique. `ksp-job-backfill-lib` conserve de son côté son rôle historique paramétré et borné ; les deux producteurs restent indépendants et convergent uniquement vers les mêmes contrats RAW/Store. +`ksp-worker-raw-transaction-ingest-lib` est le premier Worker concret distinct du Job Backfill. Il conserve sa fondation Start/Stop, admission bornée, Common RAW, Store backend-neutral, shutdown borné et snapshots latest-value, et possède maintenant une première source productive Yellowstone + hydration HTTP `getTransaction`. Les signaux `Transaction`, `TransactionStatus` et transactions de `Block` sont coalescés puis hydratés avant admission RAW ; `BlockMeta` et `Slot` restent des signaux de continuité. Le reconnect/replay reste propriétaire de Transport, la frontier de traitement reste run-local et un gap de rétention prouvé provoque un fault au lieu de lancer une campagne historique. `ksp-job-backfill-lib` conserve son rôle historique paramétré et borné ; les deux producteurs restent indépendants et convergent uniquement vers les mêmes contrats RAW/Store. ## Points d'entrée diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/README.md b/crates/ksp-worker-raw-transaction-ingest-lib/README.md index 92caca2..8f71bc4 100644 --- a/crates/ksp-worker-raw-transaction-ingest-lib/README.md +++ b/crates/ksp-worker-raw-transaction-ingest-lib/README.md @@ -1,65 +1,147 @@ - + # ksp-worker-raw-transaction-ingest-lib -`ksp-worker-raw-transaction-ingest-lib` est le premier Worker concret de KSP pour l'alimentation continue de la couche RAW Transaction. +`ksp-worker-raw-transaction-ingest-lib` est le Worker concret KSP chargé de l'alimentation continue de la couche RAW Transaction. -La crate fournit la fondation runtime **source-neutral** du Worker : identité et settings bornés, lifecycle Start/Stop, admission privée bornée, canonicalisation via `ksp-raw-transaction-lib`, persistance backend-neutral via `ksp-store-lib`, supervision des tâches, shutdown borné et snapshots latest-value projetables sur `ksp-worker-api`. - -La fondation ne contient volontairement encore **aucune source réseau productive**. Elle ne dépend pas de `ksp-onchain-transport-lib` et n'expose pas d'API publique permettant au caller d'injecter directement des transactions dans la queue interne. Les adapters live/catch-up sont des responsabilités ultérieures du même Worker, pas de son API de fondation. - -## Identité et réseau - -Une exécution est liée à : +La crate possède deux niveaux publics complémentaires : ```text -RawNetworkId -WorkerId -Worker kind = raw_transaction_ingest +RawTransactionIngestWorker::start + -> fondation source-neutral, sans source productive + +RawTransactionIngestWorker::start_with_runtime_resources + -> même runtime + une source Yellowstone productive supervisée + + hydration HTTP getTransaction ``` -Le réseau logique doit être identique à celui du `Store` remis au démarrage. La transaction canonique conserve l'identité durable définie par la couche RAW commune ; le Worker n'ajoute ni provider, ni endpoint, ni protocole à cette identité. +Le Worker reste indépendant de Config et de tout backend Store physique. Le caller compose les ressources Transport et Store, puis les remet à la crate par ses façades publiques. -## Runtime +## Pipeline productif actuel -Le point d'entrée public est : +La première verticale live est : ```text -RawTransactionIngestWorker::start(settings, Arc) - -> RawTransactionIngestHandle +Yellowstone standard subscribe + -> Transaction / TransactionStatus / Block + -> signal source-neutral (network, signature, slot, commitment, provenance sûre) + -> coalescence bornée par (network, signature, commitment) + -> HTTP getTransaction observed + -> ksp-raw-transaction-lib + -> admission centrale bornée + -> ksp-store-lib + -> RawTransaction + RawTransactionObservation ``` -Le démarrage est synchrone mais nécessite qu'un runtime Tokio courant appartienne déjà au caller. Le Worker ne crée pas de runtime global et n'expose aucun `JoinHandle` public. +`BlockMeta` et `Slot` ne produisent pas de RAW directement. Ils servent uniquement à la projection de continuité du run. + +La qualification reste conservative : même lorsqu'une update Yellowstone contient une transaction complète côté protobuf, le Worker hydrate actuellement les signaux transactionnels par HTTP `getTransaction` avant de construire le RAW canonique. Il n'existe donc pas de second canonicaliseur Yellowstone. + +## Contrat de source Yellowstone + HTTP + +`RawTransactionIngestYellowstoneSource::new` reçoit : + +```text +YellowstoneGrpcChannel +YellowstoneSubscribeRequest +HttpTransportPool +HttpRoleName d'hydration +``` + +La construction est sans I/O et refuse notamment : + +- une requête Yellowstone invalide ; +- l'absence de famille porteuse d'ingestion ; +- un commitment `Processed` ou implicite ; +- un réseau Yellowstone non représentable ; +- une provenance provider/endpoint non représentable ; +- l'absence d'une route HTTP compatible pour `getTransaction` sur le même réseau. + +Le runtime-resource aggregate public contient exactement une source Yellowstone validée. Il n'expose ni enum provider, ni collection de sources, ni callback, ni queue d'enqueue, ni client inférieur. + +## Runtime et lifecycle + +Le Worker s'exécute sur le runtime Tokio courant du caller. Il ne crée pas de runtime global et n'expose aucun `JoinHandle` public. `RawTransactionIngestHandle` permet de : - demander un stop coopératif et idempotent ; -- obtenir une source de snapshots concrets latest-value ; -- utiliser cette même source via `WorkerSnapshotSource` ; -- attendre le terminal après drain/abort+join des tâches possédées. +- lire une source de snapshots concrets latest-value ; +- utiliser la même source via `WorkerSnapshotSource` ; +- attendre le terminal après drain et join des tâches possédées. -La destruction du dernier handle de contrôle ferme aussi la voie de contrôle privée ; le runtime termine alors selon les mêmes règles de shutdown. +Le shutdown est borné par `shutdown_drain_timeout`. Les tâches source, hydration et persistence possédées sont drainées ou abort+join avant publication terminale. L'abandon terminal d'une hydration retire son pending run-local sans le convertir artificiellement en travail `settled`. -## Admission et Common RAW +## Admission, coalescence et backpressure -La queue centrale est un `tokio::sync::mpsc` privé borné par `admission_queue_capacity`. Les sources internes doivent subir la backpressure du channel ; aucune queue non bornée ni silent drop n'est autorisé. +La queue centrale est un `tokio::sync::mpsc` privé borné par `admission_queue_capacity`. Les sources internes subissent la backpressure ; aucune queue non bornée ni silent drop n'est autorisé. -Chaque ingress admis est : +La source Yellowstone possède également un coordinateur d'hydration borné : -1. vérifié contre le réseau attendu ; -2. canonicalisé exclusivement par `ksp-raw-transaction-lib` ; -3. associé à une observation key déterministe sous le domaine `ksp.raw_transaction_ingest.observation.v1` ; -4. assemblé en acquisition RAW commune ; -5. remis à la persistence Store. +```text +in-flight hydration <= persistence_concurrency +pending source signals <= 65_536 +``` -La crate ne possède pas un second format RAW et ne duplique pas le canonicaliseur commun. +Les signaux partageant le même `(network, signature, commitment)` sont coalescés avant le fan-out HTTP. Les provenances utiles restent néanmoins conservées pour les ingress produits après hydration. + +Les retries/reroutages HTTP appartiennent à `ksp-onchain-transport-lib`. Le Worker ne possède pas une seconde boucle de retry autour de `getTransaction`. + +## Processing frontier run-local + +Le snapshot expose : + +```text +hydration_pending +processing_frontier_slot +oldest_pending_slot +``` + +Cette frontier mesure uniquement le traitement des signaux réellement observés pendant le run courant. Elle n'est ni un checkpoint durable, ni une preuve de complétude blockchain, ni un curseur de Backfill. + +Un signal transactionnel devient pending après validation de sa clé d'hydration et insertion dans le coordinateur. Il devient settled pour la source lorsque : + +```text +getTransaction -> Missing +ou +getTransaction -> Available puis ingress envoyé avec succès vers l'admission centrale +``` + +Un `BlockMeta` ou `Slot` continuity-only est settled localement sans produire de RAW. La frontier n'avance jamais à travers le plus ancien pending connu. + +## Reconnect, replay et continuité + +Le reconnect/replay Yellowstone appartient à Transport. Le Worker n'écrit pas `from_slot` et n'interprète pas directement `SubscribeReplayInfo`. + +Le snapshot Worker projette uniquement des informations sûres : + +```text +source_state +source_reconnect_total +source_replay_attempt_total +source_continuity_gap_total +``` + +`RawTransactionIngestSourceState` distingue : + +```text +Active +Reconnecting +Closing +Closed +Failed +``` + +Un replay attempt n'est pas une preuve de replay réussi ni de continuité parfaite. Si Transport augmente son compteur de continuity gap parce que la borne de rétention prouve que le slot demandé n'est plus rejouable, le Worker classe la source en failure et termine avec `worker_raw_transaction_ingest.source_failed`. + +Le Worker ne lance alors ni Job Backfill ni campagne historique automatique. ## Persistence Store -La persistance passe uniquement par `ksp-store-lib` avec `default-features = false` dans la crate Worker. Aucun backend physique n'est imposé ou importé directement. +La persistance passe exclusivement par `ksp-store-lib` avec `default-features = false`. Aucun backend physique n'est importé directement. -L'écriture utilise le mode normal d'acquisition atomique `RawTransaction + RawTransactionObservation`. Les outcomes distingués sont notamment : +L'écriture utilise le mode normal atomique `RawTransaction + RawTransactionObservation`. Les outcomes distingués incluent : ```text entity inserted @@ -72,21 +154,13 @@ content conflict store failure ``` -`persistence_concurrency` borne le nombre d'écritures Store simultanées. Un conflit de contenu est terminal et n'est jamais converti en succès idempotent. +Un content conflict est terminal et n'est jamais converti en succès idempotent. -## Shutdown et faults +## Snapshots et erreurs -Le shutdown possède une deadline bornée par `shutdown_drain_timeout`. +`RawTransactionIngestSnapshotSource` est latest-value : les lecteurs peuvent rater des transitions intermédiaires mais récupèrent toujours la dernière projection complète et monotone. -Avant publication terminale, le supervisor : - -- arrête les nouvelles admissions ; -- signale le stop aux sources privées ; -- draine le travail déjà admis tant que la deadline le permet ; -- récolte les persistences et sources possédées ; -- en cas de timeout, abort les tâches restantes puis les rejoint avant le terminal. - -Les codes d'erreur publics du Worker sont : +Les codes Worker publics sont : ```text worker_raw_transaction_ingest.settings_invalid @@ -98,26 +172,7 @@ worker_raw_transaction_ingest.source_failed worker_raw_transaction_ingest.drain_timeout ``` -Les diagnostics ne recopient pas de payload RAW, URL, credential, signature hostile ou texte backend/provider arbitraire. - -## Snapshots - -`RawTransactionIngestSnapshotSource` est latest-value. Les listeners peuvent rater des états intermédiaires mais obtiennent toujours une valeur complète et monotone par `WorkerSnapshotSequence`. - -Le snapshot concret expose notamment : - -```text -lifecycle / health / activity -admission_queue_capacity / admission_queue_depth -persistence_concurrency / in_flight_persistence -admitted_total / canonicalized_total / persisted_total -entity_inserted_total / entity_already_present_total / entity_skipped_purged_total -observation_inserted_total / observation_already_present_total -content_conflict_total / store_failure_total / source_failure_total -backpressure_wait_total -``` - -Les compteurs ne wrapent jamais silencieusement. +Les diagnostics et `Debug` ne recopient pas de payload RAW, signature, URL, credential, filtre provider, texte backend/provider arbitraire ou client inférieur. ## Dépendances @@ -126,6 +181,7 @@ Les dépendances normales sont exactement : ```text ksp-core-lib ksp-logging-lib +ksp-onchain-transport-lib ksp-raw-transaction-lib ksp-store-lib (default-features = false) ksp-worker-api @@ -133,25 +189,25 @@ sha2 tokio (macros, rt, sync, time) ``` -La crate ne dépend pas de Config, Job, `ksp-store-api` directement, backend Store concret, Transport, Tauri ou SDK provider. +La crate ne dépend pas de Config, Job, `ksp-store-api` directement, backend Store concret, `reqwest`, `tonic`, `yellowstone-grpc-proto` ou Tauri. -## Hors périmètre de la fondation source-neutral +## Hors périmètre -Cette surface ne possède pas encore : +La verticale actuelle ne possède pas : -- adapter HTTP/WS/Yellowstone productif ; -- sélection Config de sources/endpoints/credentials ; -- discovery/hydration/replay de continuité live ; -- hot reconfiguration de listeners/sources ; +- plusieurs sources productives simultanées dans `RawTransactionIngestRuntimeResources` ; +- source WS/Helius-specific ou HTTP polling Worker ; +- sélection Config interne au Worker ; +- checkpoint persistent de processing frontier ; +- campagne de réparation historique automatique ; - application Desk ou process autonome ; -- campagne historique/backfill ; - décodage STRUCTURAL/DECODED/DOMAIN. -Ces extensions doivent conserver la séparation avec `ksp-job-backfill-lib` et réutiliser les mêmes contrats RAW/Store. +Les futures extensions doivent conserver la séparation avec `ksp-job-backfill-lib` et réutiliser les mêmes contrats Common RAW/Store. ## Documentation -- [`USAGE.md`](USAGE.md) — utilisation de la façade publique actuelle ; +- [`USAGE.md`](USAGE.md) — utilisation de la façade publique ; - [`../ksp-worker-api/README.md`](../ksp-worker-api/README.md) — contrats Worker génériques ; - [`../ksp-raw-transaction-lib/README.md`](../ksp-raw-transaction-lib/README.md) — canonicalisation RAW commune ; - [`../../docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md`](../../docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md) — séparation Worker/Job ; diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md b/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md index 6650aa1..96206b1 100644 --- a/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md +++ b/crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md @@ -1,9 +1,9 @@ - + # Utilisation de ksp-worker-raw-transaction-ingest-lib -Cette page décrit l'utilisation de la façade publique source-neutral de `ksp-worker-raw-transaction-ingest-lib`. Le caller possède la composition du runtime Tokio et du `Store` ; la crate Worker ne construit ni Config, ni backend physique, ni Transport. +Cette page décrit la façade publique de `ksp-worker-raw-transaction-ingest-lib`. Le caller possède la composition du runtime Tokio, du `Store` et des ressources Transport ; le Worker ne lit pas Config, ne construit pas un backend physique et ne lit pas de secret depuis l'environnement. ## Construire les settings @@ -19,20 +19,14 @@ fn worker_settings() -> ksp_core_lib::Result value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; - return std::result::Result::Ok(ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestSettings::with_defaults( - network, - worker_id, - )); + return std::result::Result::Ok(ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestSettings::with_defaults(network, worker_id)); } ``` Le Worker kind est fixe : ```rust -assert_eq!( - ksp_worker_raw_transaction_ingest_lib::RAW_TRANSACTION_INGEST_WORKER_KIND_CODE, - "raw_transaction_ingest", -); +assert_eq!(ksp_worker_raw_transaction_ingest_lib::RAW_TRANSACTION_INGEST_WORKER_KIND_CODE, "raw_transaction_ingest"); ``` Pour des limites explicites : @@ -57,22 +51,85 @@ shutdown_drain_timeout 100 ms ..= 30 s défaut 5 s Une valeur hors borne retourne `worker_raw_transaction_ingest.settings_invalid` avec uniquement le nom stable du champ invalide. -## Démarrer sur le runtime du caller +## Choisir le mode de démarrage -`RawTransactionIngestWorker::start` doit être appelé depuis un contexte possédant déjà un runtime Tokio courant. Le `Store` est passé dans un `Arc` et doit cibler exactement le même `RawNetworkId` que les settings. +### Fondation sans source productive + +`RawTransactionIngestWorker::start(settings, store)` démarre la fondation runtime sans source Transport. Ce mode reste utile aux tests/compositions qui veulent uniquement le lifecycle, les snapshots et le contrat de shutdown. ```rust -async fn start_worker( - settings: ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestSettings, - store: std::sync::Arc, -) -> ksp_core_lib::Result { - return ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestWorker::start(settings, store); +let handle = match ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestWorker::start(settings, store) { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), +}; +``` + +### Source Yellowstone productive + +Pour l'ingestion live, le caller compose d'abord les ressources via les crates propriétaires, puis construit : + +```rust +fn runtime_resources( + yellowstone_channel: ksp_onchain_transport_lib::YellowstoneGrpcChannel, + subscribe_request: ksp_onchain_transport_lib::YellowstoneSubscribeRequest, + http_pool: ksp_onchain_transport_lib::HttpTransportPool, + hydration_role: ksp_onchain_transport_lib::HttpRoleName, +) -> ksp_core_lib::Result { + let source = match ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestYellowstoneSource::new( + yellowstone_channel, + subscribe_request, + http_pool, + hydration_role, + ) { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), + }; + return std::result::Result::Ok(ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestRuntimeResources::new(source)); } ``` -Le démarrage retourne avant la fin du Worker. Aucun `JoinHandle` Tokio n'est exposé au caller. +Puis : -Un appel hors runtime Tokio courant retourne une erreur `worker_raw_transaction_ingest.runtime_invalid`. Un mismatch réseau Store/settings est également rejeté avant le spawn. +```rust +let handle = match ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestWorker::start_with_runtime_resources( + settings, + store, + runtime_resources, +) { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), +}; +``` + +Les deux entrées exigent un runtime Tokio courant et un `Store` portant exactement le même `RawNetworkId` que les settings. Le démarrage avec ressources exige également que la source Yellowstone/HTTP cible ce même réseau. + +## Préparer la source Yellowstone + +La `YellowstoneSubscribeRequest` doit : + +- être valide selon Transport ; +- contenir au moins une famille transaction-bearing admise par le Worker ; +- utiliser explicitement `Confirmed` ou `Finalized` ; +- rester compatible avec le réseau du `YellowstoneGrpcChannel`. + +Le `HttpTransportPool` doit posséder au moins une route compatible avec le rôle d'hydration et `getTransaction` sur le même réseau. La construction de `RawTransactionIngestYellowstoneSource` vérifie ces invariants sans ouvrir la connexion réseau. + +Le caller ne passe pas de signature, `program_id`, plage de slots ou limite historique au Worker. Ces paramètres appartiennent à un Job Backfill, pas au service continu. + +## Comprendre la pipeline live + +Les familles Yellowstone sont traitées ainsi : + +```text +Transaction -> signal -> HTTP getTransaction -> Common RAW -> admission +TransactionStatus -> signal -> HTTP getTransaction -> Common RAW -> admission +Block -> un signal par transaction -> HTTP getTransaction -> Common RAW -> admission +BlockMeta -> continuity-only +Slot -> continuity-only +Account/Ping/Pong/Entry -> sans RAW Transaction dans cette verticale +``` + +Les signaux de même `(network, signature, commitment)` sont coalescés avant l'hydration HTTP. Le Worker ne possède pas une boucle de retry HTTP : reroutage/retry/backoff restent dans `ksp-onchain-transport-lib`. ## Observer le snapshot concret @@ -84,6 +141,10 @@ let sequence = current.worker_snapshot().sequence(); let state = current.worker_snapshot().state(); let queue_depth = current.admission_queue_depth(); let in_flight = current.in_flight_persistence(); +let hydration_pending = current.hydration_pending(); +let frontier = current.processing_frontier_slot(); +let oldest_pending = current.oldest_pending_slot(); +let source_state = current.source_state(); ``` Pour attendre une valeur plus récente : @@ -94,7 +155,7 @@ let newer = source.wait_for_change(observed).await; assert!(newer.worker_snapshot().sequence().is_after(observed)); ``` -Le flux est latest-value : les transitions intermédiaires peuvent être coalescées. Ne pas l'utiliser comme journal d'événements exhaustif. +Le flux est latest-value : les transitions intermédiaires peuvent être coalescées. Ne pas l'utiliser comme journal exhaustif. ## Utiliser la projection Worker API @@ -108,11 +169,9 @@ let newer = ksp_worker_api::WorkerSnapshotSource::wait_for_change(&source, obser assert!(newer.sequence().is_after(observed)); ``` -Cette projection commune ne contient que les dimensions génériques Worker. Les compteurs d'admission/persistence restent disponibles sur `RawTransactionIngestSnapshot`. +La projection commune contient seulement les dimensions génériques Worker. Les compteurs et frontiers spécifiques restent sur `RawTransactionIngestSnapshot`. -## Lire les compteurs concrets - -Les compteurs principaux sont monotones : +## Lire les compteurs ```rust let snapshot = handle.snapshot_source().current(); @@ -128,11 +187,43 @@ let conflicts = snapshot.content_conflict_total(); let store_failures = snapshot.store_failure_total(); let source_failures = snapshot.source_failure_total(); let backpressure = snapshot.backpressure_wait_total(); +let reconnects = snapshot.source_reconnect_total(); +let replay_attempts = snapshot.source_replay_attempt_total(); +let proven_gaps = snapshot.source_continuity_gap_total(); ``` -`admission_queue_depth()` et `in_flight_persistence()` sont des gauges latest-value, pas des totaux cumulés. +`admission_queue_depth()`, `in_flight_persistence()` et `hydration_pending()` sont des gauges latest-value. Les compteurs cumulés ne wrapent jamais silencieusement ; l'épuisement est terminal avec `worker_raw_transaction_ingest.counter_exhausted`. -L'épuisement d'un compteur ou de la séquence est terminal et utilise `worker_raw_transaction_ingest.counter_exhausted` au lieu de wrapper silencieusement. +## Interpréter la processing frontier + +`processing_frontier_slot()` est la plus haute slot de travail source réellement observé qui n'est pas bloquée par un pending plus ancien connu. `oldest_pending_slot()` expose ce plus ancien pending lorsqu'il existe. + +Cette frontier est strictement run-local : + +```text +elle ne prouve pas que toutes les transactions blockchain d'une slot ont été observées +elle ne prouve pas la persistence durable des ingress déjà envoyés à l'admission +elle n'est pas persistée entre deux runs +elle n'est pas un checkpoint Backfill +``` + +Un `Missing` HTTP règle le signal du point de vue source-processing sans créer de RAW. Un ingress `Available` n'est réglé qu'après envoi réussi vers l'admission centrale. Une hydration abandonnée au shutdown est retirée des pending sans faire avancer artificiellement la frontier. + +## Interpréter reconnect et replay + +`source_state()` peut retourner `Active`, `Reconnecting`, `Closing`, `Closed` ou `Failed` après démarrage de la source productive. + +Les compteurs ont des sémantiques distinctes : + +```text +source_reconnect_total reconnects automatiques réussis observés +source_replay_attempt_total tentatives de reconnect portant une demande de replay +source_continuity_gap_total gaps de rétention prouvés par Transport +``` + +Une tentative de replay n'est pas une preuve de continuité. Le Worker ne choisit pas `from_slot` et ne traite pas directement `SubscribeReplayInfo` ; ces mécanismes appartiennent à Transport. + +Si `source_continuity_gap_total` augmente, le Worker fault avec `worker_raw_transaction_ingest.source_failed`. Il ne déclenche pas automatiquement `ksp-job-backfill-lib`. ## Demander un stop et attendre le terminal @@ -152,55 +243,37 @@ if accepted { } ``` -`request_stop()` est idempotent. Il exprime une intention coopérative ; le terminal n'est publié qu'après traitement du drain et des tâches possédées. +`request_stop()` est idempotent. Le terminal n'est publié qu'après le drain borné et la récupération des tâches possédées. -Le shutdown est borné par `shutdown_drain_timeout`. Si les tâches ne peuvent pas être drainées à temps, le Worker les abort puis les rejoint avant de publier `worker_raw_transaction_ingest.drain_timeout`. - -## Interpréter les terminaux faultés - -Les codes Worker publics sont : +## Interpréter les faults ```text settings_invalid settings techniques hors contrat runtime_invalid invariant runtime/lifecycle impossible store_failed erreur Store non-conflict classifiée -content_conflict transaction canonique incompatible avec le contenu durable +content_conflict contenu canonique incompatible avec l'identité durable counter_exhausted compteur/séquence monotone arrivé à sa borne -source_failed tâche source privée terminée en erreur -drain_timeout drain du shutdown hors deadline +source_failed source/replay/hydration terminée par une erreur classifiée +drain_timeout drain de shutdown hors deadline ``` -Un consumer doit traiter le `ErrorCode` comme contrat stable et ne pas dépendre d'un texte backend/provider arbitraire. - -## Frontière d'admission - -La queue d'admission et le type ingress sont volontairement privés. La façade publique actuelle ne propose ni `send`, ni `enqueue`, ni registration d'un adapter réseau. - -Les adapters d'acquisition qui alimentent cette queue appartiennent à l'implémentation du Worker et doivent conserver : - -```text -backpressure mpsc bornée -stop prioritaire sur send bloqué -canonicalisation via ksp-raw-transaction-lib -persistance via ksp-store-lib -aucun backend physique direct -aucun provider dans l'identité canonique -``` - -Le caller ne doit pas contourner cette frontière en écrivant directement dans les structures privées du Worker. +Un consumer doit traiter l'`ErrorCode` comme contrat stable et ne pas dépendre d'un texte backend/provider arbitraire. ## Composition supérieure -Le pattern de composition attendu reste : +Le pattern attendu est : ```text Config / application / service owner + -> résout endpoints, credentials et rôles + -> construit YellowstoneGrpcChannel + YellowstoneSubscribeRequest + -> construit HttpTransportPool + hydration role -> construit le Store - -> choisit ultérieurement les sources/adapters supportés + -> construit RawTransactionIngestRuntimeResources -> construit RawTransactionIngestSettings - -> démarre RawTransactionIngestWorker + -> démarre RawTransactionIngestWorker::start_with_runtime_resources -> observe RawTransactionIngestSnapshotSource -> demande stop lorsque nécessaire ``` -Le Worker ne reçoit pas de requête historique métier. Une campagne `signature/program_id/plage/limite` appartient à `ksp-job-backfill-lib`, pas à ce runtime continu. +Le Worker ne reçoit pas de requête historique métier et ne dépend pas de Config. Une campagne `signature/program_id/plage/limite` appartient à `ksp-job-backfill-lib`. diff --git a/deltas/0.3.12/pre.012.md b/deltas/0.3.12/pre.012.md new file mode 100644 index 0000000..ff3c0b1 --- /dev/null +++ b/deltas/0.3.12/pre.012.md @@ -0,0 +1,71 @@ + + + +# Delta `0.3.12-pre.012` + +## Base + +`0.3.12-pre.011`. + +## Objectif + +Réconcilier la documentation durable du Worker RawTransaction avec la verticale Yellowstone + hydration HTTP + continuité réellement matérialisée et avec les preuves `pre.011`, sans changer le runtime ni préparer encore la publication. + +## Fichiers ajoutés + +- `deltas/0.3.12/pre.012.md`. + +## Fichiers modifiés + +- `Cargo.toml` ; +- `README.md` ; +- `crates/ksp-worker-raw-transaction-ingest-lib/README.md` ; +- `crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md` ; +- `docs/architecture/004-COMPONENT_INVENTORY.md` ; +- `docs/architecture/005-DEPENDENCY_GRAPH.md` ; +- `docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md` ; +- `docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md` ; +- `docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md`. + +## Fichiers supprimés + +Aucun. + +## Décisions + +- la version workspace devient `0.3.12-pre.12` ; +- aucun fichier Rust de production ou de test n'est modifié ; +- la documentation Worker décrit désormais la première source productive Yellowstone et l'hydration HTTP `getTransaction` ; +- `RawTransactionIngestWorker::start` reste la fondation sans source, `start_with_runtime_resources` est l'entrée productive ; +- les signaux `Transaction`, `TransactionStatus` et `Block` sont hydratés avant Common RAW ; `BlockMeta`/`Slot` restent continuity-only ; +- la processing frontier est explicitement run-local et non durable ; +- reconnect, `from_slot` et `SubscribeReplayInfo` restent propriétaires de Transport ; +- un gap de rétention prouvé provoque un fault Worker et ne déclenche aucun Backfill automatique ; +- le graphe durable matérialise l'edge Worker -> `ksp-onchain-transport-lib` sans déplacer Config, backend Store ou clients inférieurs dans le Worker ; +- le gate déterministe `pre.011` et les deux smokes keyless PASS sont enregistrés ; +- les smokes Yellowstone/Worker non réellement exécutés restent explicitement NON EXÉCUTÉS ; +- `CHANGELOG.md`, `ROADMAP.md` et le prompt suivant ne sont pas modifiés. + +## Validations exécutées dans l'environnement d'assemblage + +- `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` ; +- recherche des formulations durables obsolètes sur le Worker ; +- vérification d'inventaire du delta ; +- `unzip -t` ; +- reproduction byte-à-byte du delta sur `0.3.12-pre.011`. + +## Validations non exécutées localement + +`cargo`, `rustc` et `rustfmt` ne sont pas installés dans l'environnement d'assemblage. Aucun PASS Cargo local n'est revendiqué pour `pre.012`. + +## Gate opérateur requis + +```bash +cargo fmt --all -- --check +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-worker-raw-transaction-ingest-lib +``` diff --git a/docs/architecture/004-COMPONENT_INVENTORY.md b/docs/architecture/004-COMPONENT_INVENTORY.md index e67d089..71dbc95 100644 --- a/docs/architecture/004-COMPONENT_INVENTORY.md +++ b/docs/architecture/004-COMPONENT_INVENTORY.md @@ -1,5 +1,5 @@ - + # Inventaire initial des composants KSP @@ -46,7 +46,7 @@ Ce document maintient l'inventaire synthétique des composants retenus ou presse | Store Desk | `ksp-app-store-desk` | app | Implémenté | `0.3.8` | inspection RAW read-only Transaction/Account/Observation via façade Store | | RAW transaction common | `ksp-raw-transaction-lib` | lib | Implémenté | `0.3.10` | canonicalisation/wire RAW Transaction v1 source-neutral partagé entre producteurs | | Worker lifecycle | `ksp-worker-api` | API | Implémenté | `0.3.9` | lifecycle/health/progression génériques des services continus | -| RAW transaction worker | `ksp-worker-raw-transaction-ingest-lib` | worker/lib | Implémenté | `0.3.11`, extensions `0.3.12+` | fondation source-neutral, puis sources live multi-source/recovery | +| RAW transaction worker | `ksp-worker-raw-transaction-ingest-lib` | worker/lib | Implémenté | `0.3.11`, live `0.3.12` | fondation + Yellowstone productif, hydration HTTP, frontier/reconnect run-local | | RAW ingest Desk | `ksp-app-raw-transaction-ingest-desk` | app | Retenu | `0.3.15` | choix/supervision d’une ou plusieurs sources/méthodes sans réimplémenter le worker | | STRUCTURAL job | nom à fixer | job/lib | Retenu | couche STRUCTURAL | normalisation Solana générique RAW -> STRUCTURAL bornée/rejouable | | STRUCTURAL worker | nom à fixer | worker/lib | Retenu | fin couche STRUCTURAL | backlog RAW -> STRUCTURAL continu | diff --git a/docs/architecture/005-DEPENDENCY_GRAPH.md b/docs/architecture/005-DEPENDENCY_GRAPH.md index ca62761..1c8ffcc 100644 --- a/docs/architecture/005-DEPENDENCY_GRAPH.md +++ b/docs/architecture/005-DEPENDENCY_GRAPH.md @@ -1,5 +1,5 @@ - + # Graphe de dépendances KSP @@ -419,9 +419,10 @@ Il remplit RAW et ne décode aucun programme. Il ne dépend pas de Config : la c ksp-worker-api -> ksp-core-lib -ksp-worker-raw-transaction-ingest-lib # fondation source-neutral matérialisée +ksp-worker-raw-transaction-ingest-lib # fondation + première source live matérialisées -> ksp-core-lib -> ksp-logging-lib + -> ksp-onchain-transport-lib # Yellowstone subscribe + HTTP getTransaction observed -> ksp-raw-transaction-lib -> ksp-store-lib # default-features = false ; aucun backend imposé -> ksp-worker-api @@ -432,9 +433,9 @@ ksp-worker-control-lib # composant retenu, non matérialis -> ksp-core-lib ``` -`ksp-worker-api` est ouvert en `0.3.9` comme contrat générique de services continus et ne connaît ni Solana, ni Transport, ni Store, ni Tauri. `ksp-worker-raw-transaction-ingest-lib` est son premier consumer concret : sa fondation `0.3.11` est source-neutral, possède admission/persistence/snapshots/shutdown, et ne dépend pas encore de Transport. Les adapters live sont ajoutés ensuite sans déplacer Config ni backend physique dans le Worker. +`ksp-worker-api` est ouvert en `0.3.9` comme contrat générique de services continus et ne connaît ni Solana, ni Transport, ni Store, ni Tauri. `ksp-worker-raw-transaction-ingest-lib` est son premier consumer concret : sa fondation `0.3.11` possède admission/persistence/snapshots/shutdown ; l'extension live `0.3.12` ouvre l'edge direct vers `ksp-onchain-transport-lib` pour une source Yellowstone standard et l'hydration HTTP `getTransaction`. Config et le backend physique restent hors du Worker. -La cible live n'est pas « un worker WebSocket » ou « un worker gRPC ». Les tranches de sources peuvent ajouter `ksp-onchain-transport-lib` lorsque l'adapter productif le nécessite et composer des stratégies alternatives, complémentaires (discovery + hydration), redondantes entre providers ou spécialisées live/catch-up/gap-repair. La transaction canonique reste identifiée indépendamment de la source et chaque acquisition utile conserve sa propre observation/provenance Store. +La verticale actuelle n'est ni « un worker WebSocket » ni un moteur historique : `RawTransactionIngestRuntimeResources` contient exactement une source Yellowstone validée, les signaux transactionnels sont hydratés par HTTP avant Common RAW, et `BlockMeta`/`Slot` restent continuity-only. Reconnect, `from_slot` et `SubscribeReplayInfo` restent propriétaires de Transport ; le Worker observe leur projection sûre et fault sur un gap de rétention prouvé sans appeler le Job Backfill. Les extensions multi-source restent ultérieures. RAW worker puis STRUCTURAL worker sont introduits à la fin de leur couche respective, lorsque persistence/backlog sont disponibles. Le traitement RAW -> STRUCTURAL borné est porté par un STRUCTURAL job distinct du service continu. Les workers DECODED/DOMAIN sont introduits avec les groupes Program concernés plutôt que tous anticipés en bloc. diff --git a/docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md b/docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md index 510a807..231c507 100644 --- a/docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md +++ b/docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md @@ -1,5 +1,5 @@ - + # Acquisition, workers, jobs et pipelines spécialisés @@ -102,7 +102,7 @@ ksp-worker-raw-transaction-ingest-lib Sa responsabilité est l'acquisition **continue** de `RawTransaction` puis la persistance via `ksp-store-lib`. Il ne décode pas de Program, ne possède aucun SQL/backend physique et ne fait pas de la source réseau une partie de l'identité canonique de transaction. -La fondation matérialisée possède déjà le lifecycle continu, les settings techniques bornés, la queue d'admission privée bornée, la canonicalisation Common RAW, la persistance atomique backend-neutral, les snapshots latest-value et le shutdown borné. Elle ne possède encore aucune source réseau productive et n'a donc aucun edge Transport ; les adapters live/catch-up complètent ensuite ce même Worker sans ouvrir de second runtime parallèle. +Le Worker matérialisé possède le lifecycle continu, les settings techniques bornés, la queue d'admission privée, la canonicalisation Common RAW, la persistance atomique backend-neutral, les snapshots latest-value et le shutdown borné. Sa première source productive est désormais Yellowstone standard + hydration HTTP `getTransaction`, injectée par `RawTransactionIngestRuntimeResources` sans lecture Config interne. `Transaction`, `TransactionStatus` et les transactions de `Block` deviennent des signaux coalescés puis hydratés ; `BlockMeta` et `Slot` restent continuity-only. Le Worker n'ouvre pas un second runtime parallèle et n'expose toujours aucune API publique d'enqueue. Le modèle cible n'est pas : @@ -131,18 +131,13 @@ normalisation RawTransaction commune ksp-store-lib ``` -Une stratégie peut donc être : +Le modèle général autorise des stratégies alternatives, complémentaires ou redondantes, mais la verticale productive actuelle est volontairement plus étroite : **une** source Yellowstone + **une** voie HTTP d'hydration. Ce choix n'inscrit pas le provider ou le protocole dans l'identité RAW et ne ferme pas l'architecture future multi-source. -- **alternative** : une source choisie à la place d'une autre ; -- **complémentaire** : une source découvre une signature/slot et une autre hydrate la transaction complète ; -- **redondante** : plusieurs providers/transports observent la même transaction et produisent des observations distinctes ; -- **spécialisée** : une source live, une voie d'hydration et une voie de continuité/gap repair du run peuvent coexister avec des responsabilités différentes. - -Le worker ne doit pas être réduit à un enum superficiel `Http | WebSocket | Grpc`. La configuration/runtime doit exprimer les **capacités et rôles d'acquisition réellement nécessaires** : discovery, hydration, direct full transaction, live, replay/catch-up, gap repair, filtre, finality/commitment, reprise et limites. +Le reconnect/replay du stream est une capacité Transport. Le Worker conserve une processing frontier run-local sur le travail réellement observé, projette `Active/Reconnecting/Closing/Closed/Failed` et des compteurs reconnect/replay/gap, mais ne possède ni checkpoint durable ni campagne de gap repair. Un gap de rétention prouvé par Transport devient un fault `source_failed` ; une récupération historique éventuelle reste une responsabilité séparée du Job Backfill. #### Résultat de l'audit `0.3.9` -L'audit exhaustif est synthétisé dans [`011-RAW_TRANSACTION_ACQUISITION.md`](011-RAW_TRANSACTION_ACQUISITION.md). Il confirme qu'un besoin d'acquisition Solana/provider ne remonte pas dans `ksp-worker-api` : le contrat générique reste fermé et le Worker concret porte ses propres capabilities de sources, sans les ouvrir dans sa fondation source-neutral. +L'audit exhaustif est synthétisé dans [`011-RAW_TRANSACTION_ACQUISITION.md`](011-RAW_TRANSACTION_ACQUISITION.md). Il confirme qu'un besoin d'acquisition Solana/provider ne remonte pas dans `ksp-worker-api` : le contrat générique reste fermé et le Worker concret porte ses capabilities de source dans sa propre implémentation/runtime resources. Les familles admises par la synthèse couvrent notamment : diff --git a/docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md b/docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md index 186ee36..3aa5c39 100644 --- a/docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md +++ b/docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md @@ -1,5 +1,5 @@ - + # Acquisition et alimentation `RawTransaction` @@ -149,7 +149,7 @@ Il peut utiliser **HTTP, WS, Yellowstone gRPC, replay provider ou archive** si c ### 3.2 Worker Raw Transaction Ingest : acquisition continue start/stop -`ksp-worker-raw-transaction-ingest-lib` a pour rôle cible de **remplir continuellement Store à partir du moment où il est démarré**. Sa fondation source-neutral matérialise déjà le runtime, l'admission, la canonicalisation Common RAW, la persistence et les snapshots, mais aucune source réseau productive n'est encore branchée. +`ksp-worker-raw-transaction-ingest-lib` a pour rôle de **remplir continuellement Store à partir du moment où il est démarré**. Sa fondation runtime, l'admission, la canonicalisation Common RAW, la persistence et les snapshots sont complétés par une première source productive Yellowstone standard + hydration HTTP `getTransaction`. Son contrôle métier V1 est volontairement court : @@ -161,43 +161,49 @@ snapshot / notifications Le caller ne lui fournit pas une signature, un `program_id`, une plage historique, une limite de campagne ou une requête de backfill. Les endpoints, réseaux, sources activées, capabilities et secrets proviennent de Config/composition, pas d'un payload métier de `start`. -La fondation actuelle, lorsqu'elle démarre sans adapter source productif, publie son lifecycle/snapshot puis reste contrôlable jusqu'au stop. Dès qu'une source interne est matérialisée, le pipeline cible devient : +Deux entrées publiques coexistent : `start` conserve la fondation sans source productive, tandis que `start_with_runtime_resources` lance une source Yellowstone supervisée. Le pipeline productif actuel est : ```text -acquiert les nouvelles transactions disponibles -hydrate les signaux live incomplets si nécessaire -normalise puis persiste RawTransaction + observations -publie ses snapshots latest-value indépendamment de leurs lecteurs -continue jusqu'à stop ou fault +Yellowstone Transaction / TransactionStatus / Block + -> signaux transactionnels source-neutral + -> coalescence bornée (network, signature, commitment) + -> HTTP getTransaction observed + -> Common RAW + -> admission centrale + -> Store + +Yellowstone BlockMeta / Slot + -> continuité run-local uniquement ``` -Le Worker peut ensuite utiliser **WS, Yellowstone gRPC, HTTP, block polling, provider streams ou sources EARLY** si ces capacités servent l'acquisition live. Ces sources restent internes au Worker ; le caller ne pousse pas directement des ingress dans sa queue privée. +La source est caller-composed : le Worker ne lit pas Config et ne reçoit pas de secret. `RawTransactionIngestRuntimeResources` contient actuellement exactement une source Yellowstone validée, pas encore une collection multi-source. Il ne lance pas de campagne historique arbitraire. ### 3.3 Continuité Worker ≠ Backfill -Le Worker peut utiliser un replay ou HTTP pour **réparer une perte de continuité apparue pendant son acquisition active** : +La continuité du Worker reste limitée au run courant. Le moteur Yellowstone de Transport possède le reconnect et peut réémettre une demande `from_slot` à partir de son high-watermark observé ; le Worker ne choisit pas lui-même ce slot et ne traite pas directement `SubscribeReplayInfo`. + +Les notions restent séparées : ```text -stream actif - -> gap détecté - -> replay from_slot / HTTP hydration / block recovery - -> frontier live restauré - -> reprise du flux +Transport last_observed_slot = high-watermark du stream observé +Worker processing_frontier_slot = travail source observé et non bloqué par un pending plus ancien +Store durable = persistence des acquisitions admises +blockchain completeness = non prouvée par les métriques ci-dessus ``` -Cette réparation reste liée au frontier du Worker et ne transforme pas le Worker en moteur historique. +Une tentative de replay ne prouve ni succès ni continuité parfaite. Si Transport prouve qu'un slot demandé est antérieur à `first_available`, son compteur de continuity gap augmente ; le Worker projette ce gap puis termine avec un fault `source_failed`. -Inversement : +Il n'existe pas de délégation automatique vers Backfill : ```text -« récupère les transactions du programme X depuis le slot Y » -« récupère les 100 000 dernières signatures de cette adresse » -« rejoue cette plage d'archive » +gap de rétention prouvé + -> Worker fault/stop + -> aucun lancement de campagne historique ``` -sont des campagnes Job Backfill. +Inversement, une demande telle que « récupère les transactions du programme X depuis le slot Y » reste une campagne `ksp-job-backfill-lib`. ### 3.4 Absence de relation Job ↔ Worker @@ -657,13 +663,13 @@ ksp-worker-raw-transaction-ingest-lib ---> ksp-raw-transaction-lib ----> ksp-sto ksp-job-backfill-lib --------------------> ksp-store-lib ksp-worker-raw-transaction-ingest-lib ---> ksp-store-lib ksp-job-backfill-lib --------------------> ksp-onchain-transport-lib -ksp-worker-raw-transaction-ingest-lib -X-> ksp-onchain-transport-lib # aucun adapter live productif encore +ksp-worker-raw-transaction-ingest-lib ---> ksp-onchain-transport-lib # Yellowstone + HTTP hydration aucun edge Job <-> Worker aucun edge Transport <-> ksp-raw-transaction-lib ``` -Les tranches live suivantes peuvent matérialiser l'edge Worker -> Transport lorsqu'un adapter source productif le nécessite ; cet edge n'appartient pas à la fondation source-neutral. +L'edge Worker -> Transport est désormais productif, mais reste strictement contenu dans le Worker concret. `ksp-worker-api`, Common RAW et Store API ne gagnent aucune connaissance Transport/provider. La migration doit préserver exactement les golden bytes/hash RAW v1 déjà prouvés. Aucun RAW v2 n'est justifié. @@ -713,13 +719,13 @@ Yellowstone Transaction/Block -> signal structuré + transaction wire fidèle RAW v1 complet -> hydration HTTP avant persistence ``` -Aucun adapter productif n'est ajouté par la qualification cross-source. Conformément à `TR-C2`, l'adapter `Transport DTO -> common` demeure réservé au Worker concret. La fondation `0.3.11` est désormais matérialisée sans Transport ; le premier adapter productif reste donc une responsabilité des tranches live suivantes. +Cette qualification cross-source a préparé le contrat sans créer d'edge Common RAW -> Transport. L'extension Worker live utilise désormais cette décision conservative : Yellowstone produit des signaux structurés dans le Worker concret, puis HTTP `getTransaction` fournit le matériau RAW complet avant canonicalisation. Common RAW reste entièrement Transport-neutral. -## 14. Handoff fondation Worker `0.3.11` vers live `0.3.12` à `0.3.14` +## 14. État du Worker live après `0.3.12` -### 14.0 État fermé par la fondation source-neutral +### 14.0 Verticale matérialisée -La fondation du Worker est matérialisée avec : +La verticale productive possède : ```text consumer de ksp-worker-api @@ -727,26 +733,33 @@ settings réseau/Worker bornés start/stop sur runtime Tokio caller-owned supervision privée des tâches mpsc central borné + backpressure +une source Yellowstone standard caller-composed +Transaction / TransactionStatus / Block -> signaux transactionnels +BlockMeta / Slot -> continuity-only +coalescence bornée par network/signature/commitment +HTTP getTransaction observed pour hydration canonicalisation et assembly via ksp-raw-transaction-lib -observation key déterministe persistence atomique via ksp-store-lib en mode Normal -concurrence Store bornée -snapshots concrete + projection WorkerSnapshotSource -faults Store/content/source/counter classifiés +processing frontier run-local bornée +projection source Active/Reconnecting/Closing/Closed/Failed +observation des compteurs reconnect/replay/gap Transport +fault sur gap de rétention prouvé shutdown deadline + abort/join sans tâche orpheline ``` -Elle ne possède encore : +Elle conserve explicitement les frontières suivantes : ```text -aucun adapter HTTP/WS/Yellowstone productif -aucun edge ksp-onchain-transport-lib -aucune lecture Config +aucune lecture Config dans le Worker +aucun backend Store physique aucune API publique d'enqueue/source registration -aucun replay/gap-repair live +aucun checkpoint persistant de processing frontier +aucun appel Worker -> ksp-job-backfill-lib +aucune campagne historique automatique sur continuity gap +aucun client reqwest/tonic/proto direct hors façade Transport ``` -Cette frontière est volontaire : les tranches live ajoutent des sources au supervisor existant au lieu d'introduire un second runtime ou une API d'admission publique. +Le replay reconnect est Transport-owned. La processing frontier ne constitue pas une preuve de complétude durable ou blockchain. ### 14.1 Contrat fonctionnel @@ -755,12 +768,12 @@ Cette frontière est volontaire : les tranches live ajoutent des sources au supe ```text être un consumer de ksp-worker-api être démarré/arrêté sans requête historique métier -ouvrir les sources activées par Config +recevoir des ressources déjà composées par la couche supérieure acquérir à partir du démarrage -supporter plusieurs sources simultanées normaliser et persister RawTransaction + observations publier snapshots/notifications concrètes Worker -réparer seulement ses propres pertes de continuité live +laisser reconnect/from_slot/replay au Transport +fault proprement lorsqu'un gap de rétention est prouvé ``` Il ne doit pas : diff --git a/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md b/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md index e804d41..88ff09e 100644 --- a/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md +++ b/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md @@ -1,5 +1,5 @@ - + # Validation v0.3.12 — Yellowstone + hydration HTTP + continuité de run du Worker RawTransaction @@ -2070,3 +2070,94 @@ aucun nouveau scope fonctionnel n'est ajouté pour contourner un provider indisp ``` Dans l'environnement d'assemblage, `cargo`, `rustc` et `rustfmt` ne sont pas installés ; aucun PASS Cargo ou live local n'est revendiqué. + +## 82. Gate opérateur déterministe `pre.011` + +Le gate déterministe communiqué pour `0.3.12-pre.11` est entièrement vert. + +```text +General Rust rule audit : clean +Rust export completeness audit : 0 candidate(s) +KSP workspace Rust rule audit : clean +Markdown table audit : clean (340 tables, 821 fichiers) +cargo fmt --all -- --check : PASS +cargo check --workspace : PASS +cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS +cargo test --workspace --all-targets --all-features : PASS +``` + +Les suites ciblées requises sont également PASS, dont : + +```text +ksp-onchain-transport-lib : 388 unit PASS, 51 public_api PASS, 43 release_completeness PASS, 4 doc-tests PASS +ksp-raw-transaction-lib : 17 unit PASS + suites boundary/public/release/security PASS +ksp-store-api : 22 unit PASS + suites boundary/external/public/release/security PASS +ksp-store-lib --no-default-features : PASS +ksp-worker-raw-transaction-ingest-lib : 66 unit, 4 cross_layer, 9 boundary, 16 hardening, 9 public_api, 4 release_completeness PASS +``` + +Les trois commandes d'inspection Cargo demandées ont été exécutées jusqu'au retour du prompt opérateur : + +```text +cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal : exécuté +cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features : exécuté +cargo tree --duplicates : exécuté ; inventaire multi-version affiché +``` + +`cargo tree --duplicates` est un rapport d'inventaire et non un test booléen ; son output non vide n'est pas reclassé artificiellement en défaut de release. Les tests de dependency firewall/cross-layer restent les gates normatifs des frontières KSP. + +## 83. Smokes live keyless `pre.011` + +Les deux smokes Transport sans secret ont été exécutés explicitement après le gate déterministe : + +```text +transport_devnet_smoke + programmatic_devnet_transport_reaches_accounts_tokens_cluster_transactions_blocks_and_economics_reads + PASS : 1/1, 0 failed + +websocket_devnet_smoke + programmatic_devnet_websocket_reaches_slot_notification_then_unsubscribes_and_closes + PASS : 1/1, 0 failed +``` + +Ces preuves valident un accès live HTTP Devnet et un cycle live WebSocket Devnet. Elles ne prouvent pas Yellowstone, l'hydration Worker ou la persistence Store. + +État des smokes restant token/resource-gated : + +```text +Yellowstone OrbitFlare Devnet : NON EXÉCUTÉ dans ce gate +Yellowstone PublicNode Mainnet/Testnet : NON EXÉCUTÉ dans ce gate +Worker end-to-end Yellowstone + HTTP + Store : NON EXÉCUTÉ +PostgreSQL live proofs : hors preuve Worker pre.011 et non requis pour fermer le gate déterministe +``` + +L'absence de ces ressources ne produit aucun faux PASS. + +## 84. Réconciliation documentaire `pre.012` + +`pre.012` ne modifie aucun comportement runtime, test Rust ou dépendance de crate. La tranche réconcilie la documentation durable avec la verticale réellement matérialisée et validée : + +```text +README racine : état opérationnel Worker live corrigé +README Worker : Yellowstone + HTTP hydration + frontier/reconnect documentés +USAGE Worker : start_with_runtime_resources et snapshots live documentés +inventaire composants : mission Worker live actualisée +graphe dépendances : edge Worker -> ksp-onchain-transport-lib matérialisé +architecture Workers/Jobs : une source Yellowstone actuelle, gap prouvé -> fault +architecture RawTransaction : pipeline et frontières 0.3.12 actualisés +``` + +Les formulations obsolètes « aucune source réseau productive », « aucun edge Transport » et « premier adapter productif ultérieur » sont retirées des références durables affectées. Les plans historiques restent des traces de conception et ne sont pas réécrits rétroactivement. + +La documentation conserve explicitement les non-claims : + +```text +une seule source productive dans RawTransactionIngestRuntimeResources +pas de multi-source simultané encore +pas de checkpoint persistant de processing frontier +pas de campagne automatique de gap repair/backfill +pas de preuve live Yellowstone sans token réellement exécuté +pas de Worker end-to-end live sans Store + Yellowstone + HTTP cohérents +``` + +`CHANGELOG.md`, `ROADMAP.md` et le prompt de la version suivante restent hors scope de `pre.012` conformément au plan.