v0.3.12-pre.012

This commit is contained in:
2026-09-09 23:24:20 +02:00
parent 474b894d1c
commit 79e278064d
10 changed files with 493 additions and 193 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml # file: Cargo.toml
# version: 536 # version: 537
[workspace] [workspace]
resolver = "3" 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"] 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] [workspace.package]
version = "0.3.12-pre.11" version = "0.3.12-pre.12"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -1,5 +1,5 @@
<!-- file: README.md --> <!-- file: README.md -->
<!-- version: 12 --> <!-- version: 13 -->
# Khadhroony Solana Project # 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-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 ## Points d'entrée

View File

@@ -1,65 +1,147 @@
<!-- file: crates/ksp-worker-raw-transaction-ingest-lib/README.md --> <!-- file: crates/ksp-worker-raw-transaction-ingest-lib/README.md -->
<!-- version: 1 --> <!-- version: 2 -->
# ksp-worker-raw-transaction-ingest-lib # 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 crate possède deux niveaux publics complémentaires :
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 à :
```text ```text
RawNetworkId RawTransactionIngestWorker::start
WorkerId -> fondation source-neutral, sans source productive
Worker kind = raw_transaction_ingest
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 ```text
RawTransactionIngestWorker::start(settings, Arc<Store>) Yellowstone standard subscribe
-> RawTransactionIngestHandle -> 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 : `RawTransactionIngestHandle` permet de :
- demander un stop coopératif et idempotent ; - demander un stop coopératif et idempotent ;
- obtenir une source de snapshots concrets latest-value ; - lire une source de snapshots concrets latest-value ;
- utiliser cette même source via `WorkerSnapshotSource` ; - utiliser la même source via `WorkerSnapshotSource` ;
- attendre le terminal après drain/abort+join des tâches possédées. - 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 ; ```text
2. canonicalisé exclusivement par `ksp-raw-transaction-lib` ; in-flight hydration <= persistence_concurrency
3. associé à une observation key déterministe sous le domaine `ksp.raw_transaction_ingest.observation.v1` ; pending source signals <= 65_536
4. assemblé en acquisition RAW commune ; ```
5. remis à la persistence Store.
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 ## 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 ```text
entity inserted entity inserted
@@ -72,21 +154,13 @@ content conflict
store failure 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 : Les codes Worker publics sont :
- 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 :
```text ```text
worker_raw_transaction_ingest.settings_invalid worker_raw_transaction_ingest.settings_invalid
@@ -98,26 +172,7 @@ worker_raw_transaction_ingest.source_failed
worker_raw_transaction_ingest.drain_timeout worker_raw_transaction_ingest.drain_timeout
``` ```
Les diagnostics ne recopient pas de payload RAW, URL, credential, signature hostile ou texte backend/provider arbitraire. Les diagnostics et `Debug` ne recopient pas de payload RAW, signature, URL, credential, filtre provider, texte backend/provider arbitraire ou client inférieur.
## 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.
## Dépendances ## Dépendances
@@ -126,6 +181,7 @@ Les dépendances normales sont exactement :
```text ```text
ksp-core-lib ksp-core-lib
ksp-logging-lib ksp-logging-lib
ksp-onchain-transport-lib
ksp-raw-transaction-lib ksp-raw-transaction-lib
ksp-store-lib (default-features = false) ksp-store-lib (default-features = false)
ksp-worker-api ksp-worker-api
@@ -133,25 +189,25 @@ sha2
tokio (macros, rt, sync, time) 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 ; - plusieurs sources productives simultanées dans `RawTransactionIngestRuntimeResources` ;
- sélection Config de sources/endpoints/credentials ; - source WS/Helius-specific ou HTTP polling Worker ;
- discovery/hydration/replay de continuité live ; - sélection Config interne au Worker ;
- hot reconfiguration de listeners/sources ; - checkpoint persistent de processing frontier ;
- campagne de réparation historique automatique ;
- application Desk ou process autonome ; - application Desk ou process autonome ;
- campagne historique/backfill ;
- décodage STRUCTURAL/DECODED/DOMAIN. - 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 ## 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-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 ; - [`../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 ; - [`../../docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md`](../../docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md) — séparation Worker/Job ;

View File

@@ -1,9 +1,9 @@
<!-- file: crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md --> <!-- file: crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Utilisation de ksp-worker-raw-transaction-ingest-lib # 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 ## Construire les settings
@@ -19,20 +19,14 @@ fn worker_settings() -> ksp_core_lib::Result<ksp_worker_raw_transaction_ingest_l
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), 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( return std::result::Result::Ok(ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestSettings::with_defaults(network, worker_id));
network,
worker_id,
));
} }
``` ```
Le Worker kind est fixe : Le Worker kind est fixe :
```rust ```rust
assert_eq!( assert_eq!(ksp_worker_raw_transaction_ingest_lib::RAW_TRANSACTION_INGEST_WORKER_KIND_CODE, "raw_transaction_ingest");
ksp_worker_raw_transaction_ingest_lib::RAW_TRANSACTION_INGEST_WORKER_KIND_CODE,
"raw_transaction_ingest",
);
``` ```
Pour des limites explicites : 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. 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 ```rust
async fn start_worker( let handle = match ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestWorker::start(settings, store) {
settings: ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestSettings, std::result::Result::Ok(value) => value,
store: std::sync::Arc<ksp_store_lib::Store>, std::result::Result::Err(error) => return std::result::Result::Err(error),
) -> ksp_core_lib::Result<ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestHandle> { };
return ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestWorker::start(settings, store); ```
### 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<ksp_worker_raw_transaction_ingest_lib::RawTransactionIngestRuntimeResources> {
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 ## Observer le snapshot concret
@@ -84,6 +141,10 @@ let sequence = current.worker_snapshot().sequence();
let state = current.worker_snapshot().state(); let state = current.worker_snapshot().state();
let queue_depth = current.admission_queue_depth(); let queue_depth = current.admission_queue_depth();
let in_flight = current.in_flight_persistence(); 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 : 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)); 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 ## 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)); 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 ## Lire les compteurs
Les compteurs principaux sont monotones :
```rust ```rust
let snapshot = handle.snapshot_source().current(); let snapshot = handle.snapshot_source().current();
@@ -128,11 +187,43 @@ let conflicts = snapshot.content_conflict_total();
let store_failures = snapshot.store_failure_total(); let store_failures = snapshot.store_failure_total();
let source_failures = snapshot.source_failure_total(); let source_failures = snapshot.source_failure_total();
let backpressure = snapshot.backpressure_wait_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 ## 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 faults
## Interpréter les terminaux faultés
Les codes Worker publics sont :
```text ```text
settings_invalid settings techniques hors contrat settings_invalid settings techniques hors contrat
runtime_invalid invariant runtime/lifecycle impossible runtime_invalid invariant runtime/lifecycle impossible
store_failed erreur Store non-conflict classifiée 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 counter_exhausted compteur/séquence monotone arrivé à sa borne
source_failed tâche source privée terminée en erreur source_failed source/replay/hydration terminée par une erreur classifiée
drain_timeout drain du shutdown hors deadline 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. Un consumer doit traiter l'`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.
## Composition supérieure ## Composition supérieure
Le pattern de composition attendu reste : Le pattern attendu est :
```text ```text
Config / application / service owner Config / application / service owner
-> résout endpoints, credentials et rôles
-> construit YellowstoneGrpcChannel + YellowstoneSubscribeRequest
-> construit HttpTransportPool + hydration role
-> construit le Store -> construit le Store
-> choisit ultérieurement les sources/adapters supportés -> construit RawTransactionIngestRuntimeResources
-> construit RawTransactionIngestSettings -> construit RawTransactionIngestSettings
-> démarre RawTransactionIngestWorker -> démarre RawTransactionIngestWorker::start_with_runtime_resources
-> observe RawTransactionIngestSnapshotSource -> observe RawTransactionIngestSnapshotSource
-> demande stop lorsque nécessaire -> 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`.

71
deltas/0.3.12/pre.012.md Normal file
View File

@@ -0,0 +1,71 @@
<!-- file: deltas/0.3.12/pre.012.md -->
<!-- version: 1 -->
# 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
```

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/004-COMPONENT_INVENTORY.md --> <!-- file: docs/architecture/004-COMPONENT_INVENTORY.md -->
<!-- version: 38 --> <!-- version: 39 -->
# Inventaire initial des composants KSP # 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 | | 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 | | 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 | | 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 dune ou plusieurs sources/méthodes sans réimplémenter le worker | | RAW ingest Desk | `ksp-app-raw-transaction-ingest-desk` | app | Retenu | `0.3.15` | choix/supervision dune 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 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 | | STRUCTURAL worker | nom à fixer | worker/lib | Retenu | fin couche STRUCTURAL | backlog RAW -> STRUCTURAL continu |

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/005-DEPENDENCY_GRAPH.md --> <!-- file: docs/architecture/005-DEPENDENCY_GRAPH.md -->
<!-- version: 27 --> <!-- version: 28 -->
# Graphe de dépendances KSP # 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-worker-api
-> ksp-core-lib -> 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-core-lib
-> ksp-logging-lib -> ksp-logging-lib
-> ksp-onchain-transport-lib # Yellowstone subscribe + HTTP getTransaction observed
-> ksp-raw-transaction-lib -> ksp-raw-transaction-lib
-> ksp-store-lib # default-features = false ; aucun backend imposé -> ksp-store-lib # default-features = false ; aucun backend imposé
-> ksp-worker-api -> ksp-worker-api
@@ -432,9 +433,9 @@ ksp-worker-control-lib # composant retenu, non matérialis
-> ksp-core-lib -> 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. 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.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md --> <!-- file: docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md -->
<!-- version: 18 --> <!-- version: 19 -->
# Acquisition, workers, jobs et pipelines spécialisés # 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. 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 : Le modèle cible n'est pas :
@@ -131,18 +131,13 @@ normalisation RawTransaction commune
ksp-store-lib 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 ; 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.
- **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.
#### Résultat de l'audit `0.3.9` #### 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 : Les familles admises par la synthèse couvrent notamment :

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md --> <!-- file: docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md -->
<!-- version: 12 --> <!-- version: 13 -->
# Acquisition et alimentation `RawTransaction` # 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 ### 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 : 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`. 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 ```text
acquiert les nouvelles transactions disponibles Yellowstone Transaction / TransactionStatus / Block
hydrate les signaux live incomplets si nécessaire -> signaux transactionnels source-neutral
normalise puis persiste RawTransaction + observations -> coalescence bornée (network, signature, commitment)
publie ses snapshots latest-value indépendamment de leurs lecteurs -> HTTP getTransaction observed
continue jusqu'à stop ou fault -> 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. Il ne lance pas de campagne historique arbitraire.
### 3.3 Continuité Worker ≠ Backfill ### 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 ```text
stream actif Transport last_observed_slot = high-watermark du stream observé
-> gap détecté Worker processing_frontier_slot = travail source observé et non bloqué par un pending plus ancien
-> replay from_slot / HTTP hydration / block recovery Store durable = persistence des acquisitions admises
-> frontier live restauré blockchain completeness = non prouvée par les métriques ci-dessus
-> reprise du flux
``` ```
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 ```text
« récupère les transactions du programme X depuis le slot Y » gap de rétention prouvé
« récupère les 100 000 dernières signatures de cette adresse » -> Worker fault/stop
« rejoue cette plage d'archive » -> 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 ### 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-job-backfill-lib --------------------> ksp-store-lib
ksp-worker-raw-transaction-ingest-lib ---> ksp-store-lib ksp-worker-raw-transaction-ingest-lib ---> ksp-store-lib
ksp-job-backfill-lib --------------------> ksp-onchain-transport-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 Job <-> Worker
aucun edge Transport <-> ksp-raw-transaction-lib 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é. 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 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 ```text
consumer de ksp-worker-api consumer de ksp-worker-api
@@ -727,26 +733,33 @@ settings réseau/Worker bornés
start/stop sur runtime Tokio caller-owned start/stop sur runtime Tokio caller-owned
supervision privée des tâches supervision privée des tâches
mpsc central borné + backpressure 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 canonicalisation et assembly via ksp-raw-transaction-lib
observation key déterministe
persistence atomique via ksp-store-lib en mode Normal persistence atomique via ksp-store-lib en mode Normal
concurrence Store bornée processing frontier run-local bornée
snapshots concrete + projection WorkerSnapshotSource projection source Active/Reconnecting/Closing/Closed/Failed
faults Store/content/source/counter classifiés observation des compteurs reconnect/replay/gap Transport
fault sur gap de rétention prouvé
shutdown deadline + abort/join sans tâche orpheline shutdown deadline + abort/join sans tâche orpheline
``` ```
Elle ne possède encore : Elle conserve explicitement les frontières suivantes :
```text ```text
aucun adapter HTTP/WS/Yellowstone productif aucune lecture Config dans le Worker
aucun edge ksp-onchain-transport-lib aucun backend Store physique
aucune lecture Config
aucune API publique d'enqueue/source registration 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 ### 14.1 Contrat fonctionnel
@@ -755,12 +768,12 @@ Cette frontière est volontaire : les tranches live ajoutent des sources au supe
```text ```text
être un consumer de ksp-worker-api être un consumer de ksp-worker-api
être démarré/arrêté sans requête historique métier ê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 acquérir à partir du démarrage
supporter plusieurs sources simultanées
normaliser et persister RawTransaction + observations normaliser et persister RawTransaction + observations
publier snapshots/notifications concrètes Worker 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 : Il ne doit pas :

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md --> <!-- file: docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md -->
<!-- version: 22 --> <!-- version: 23 -->
# Validation v0.3.12 — Yellowstone + hydration HTTP + continuité de run du Worker RawTransaction # 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é. 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.