Files
2026-09-11 21:54:19 +02:00

11 KiB

Delta 0.3.14-pre.003 — observabilité latest-value de continuité WebSocket

Base requise

0.3.14-pre.002-fix.002
workspace.package.version = 0.3.14-pre.2.fix.2
deltas/0.3.14/pre.002-fix.002.md présent

Gate de la base

Le gate opérateur de 0.3.14-pre.002-fix.002 est validé avant ouverture de cette tranche :

cargo fmt --all : PASS
cargo fmt --all -- --check : PASS
audit Rust workspace rules : PASS
audit Markdown tables : PASS
cargo check --workspace : PASS
cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS
cargo test -p ksp-worker-raw-transaction-ingest-lib --all-targets --all-features : PASS

Le gate Worker comprend notamment :

114 unit tests : PASS
cross_layer_completeness : 8 PASS
dependency_boundary : 19 PASS
hardening : 27 PASS
public_api : 20 PASS
release_completeness : 5 PASS

Objectif

Implémenter strictement la tranche pre.003 du plan 035 :

ajouter dans Transport une source latest-value sûre pour les snapshots WebSocket typés
la déléguer depuis les façades Standard et Helius existantes
observer les incidents reconnect/overflow dans les sources Standard Logs, Standard Block et Helius du Worker
ancrer un incident sur le dernier slot réellement observé par cette source
borner l'incident avec le premier slot post-incident réellement reçu
conserver une terminalité conservative tant que les tranches de replay/repair ultérieures ne sont pas présentes
ne créer aucun nouveau socket, actor, retry ou repair HTTP

Cette tranche ne remplace pas encore un gap WebSocket par une réparation. Elle rend l'incident explicitement observable et bornable en réutilisant exclusivement les snapshots déjà publiés par l'actor Transport existant.

Transport — source latest-value WebSocket

WsSession possède déjà un tokio::sync::watch::Receiver<WsSessionSnapshot> interne utilisé pour snapshot() et state().

pre.003 ajoute WsSessionSnapshotSource, un observateur cloneable qui encapsule uniquement un clone de ce receiver et expose :

current() -> dernier WsSessionSnapshot sûr
wait_for_change() -> prochaine valeur latest-value, ou None si l'actor disparaît

Le type ne contient ni URL, ni credentials, ni socket, ni payload de notification. Son Debug reste fondé sur la projection sûre existante.

WsSession::snapshot_source() clone le receiver existant. Les façades :

SolanaStandardWsSession
HeliusLaserStreamWsSession

délèguent cette méthode au même WsSession physique. Aucun second runtime WebSocket n'est créé.

Worker — ancre d'incident WebSocket

Le Worker introduit un contrat crate-private RawTransactionIngestWebSocketIncidentAnchor.

Il conserve uniquement :

start_slot
end_slot optionnel
compteurs de continuity gap / overflow observés au moment de l'incident
motifs reconnect et/ou overflow

La borne de début respecte le plan 035 :

start_slot = dernier slot réellement observé par la source avant l'incident

Aucun timestamp, frontier dérivé d'une autre source ou last_slot + 1 n'est utilisé comme preuve de début.

La borne de fin est :

end_slot = premier slot réellement reçu par la même source après l'incident

Le range reste inclusif. Les validations réutilisent les bornes run-local introduites en pre.002 et rejettent notamment inversion, dépassement de plage et compteur régressif.

Si un reconnect/overflow est observé avant qu'un slot source n'ait été vu, le Worker ne fabrique pas d'historique : l'incident est source.websocket_incident_unbounded.

Worker — observation des snapshots

RawTransactionIngestProcessingFrontierReporter observe maintenant les WsSessionSnapshot Transport et maintient :

continuity gap total WebSocket
notification overflow total
ancre d'incident WebSocket éventuelle
projection de lifecycle source

Une source redevenue Active reste projetée Reconnecting tant qu'un incident ouvert n'a pas reçu sa borne post-incident. Cela évite de publier transitoirement une continuité saine alors que le gap n'est pas encore borné.

Aucune mutation de la politique de reconnect Transport n'est effectuée par le Worker.

Standard Logs et Helius transaction

Les deux sources réutilisent maintenant session.snapshot_source() en parallèle de la réception métier et des tâches d'hydration existantes.

Lorsqu'un incident est détecté :

le premier signal post-incident borne le range de manière inclusive
ce signal est quand même admis dans le coordinator d'hydration existant
aucune nouvelle notification n'est admise après cette borne dans pre.003
les signaux/tâches déjà admis sont drainés
la source termine ensuite par source.continuity_gap_proven

Ce séquencement évite de perdre artificiellement le premier événement post-incident tout en restant fail-closed tant que les tranches de repair ne sont pas implémentées.

Standard Block

La source Standard Block observe le même snapshot latest-value Transport.

Le premier bloc post-incident :

borne l'incident
projette et envoie toutes ses ingresses via l'admission centrale existante
marque ensuite le slot settled
termine enfin par source.continuity_gap_proven

Un bloc sans transaction qualifiée peut quand même fermer la borne de slot et est settled avant la terminalité conservative.

Yellowstone

Le chemin Yellowstone existant reste inchangé fonctionnellement dans cette tranche :

aucune mutation Worker de from_slot
aucun ownership Worker de SubscribeReplayInfo
aucune nouvelle tentative de replay
aucune modification du contrat Transport Yellowstone

La preuve de replay native et la distinction replay_attempt / couverture effective restent réservées à pre.004.

Tests ajoutés/étendus

Transport couvre :

source latest-value courante
publication d'un changement
fermeture de la source lorsque l'actor publisher disparaît
accessibilité crate-root de WsSessionSnapshotSource
présence des délégations Standard/Helius
réutilisation du watch actor existant sans second runtime

Worker couvre :

ancre inclusive et bornée
extension monotone d'un incident reconnect/overflow
rejet d'un incident sans motif
rejet de range inversé ou surdimensionné
incident sans slot précédent -> erreur explicite
compteurs WebSocket régressifs -> erreur explicite
reconnect et overflow successifs -> même ancre la plus ancienne
absence de socket/retry/from_slot possédé par le Worker

Fichiers ajoutés

deltas/0.3.14/pre.003.md

Fichiers modifiés

Cargo.toml
crates/ksp-onchain-transport-lib/src/lib.rs
crates/ksp-onchain-transport-lib/src/ws_protocol_session.rs
crates/ksp-onchain-transport-lib/src/ws_session.rs
crates/ksp-onchain-transport-lib/tests/public_api.rs
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs
crates/ksp-worker-raw-transaction-ingest-lib/src/continuity.rs
crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs
crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs
crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs
crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/continuity.rs
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs

Fichiers supprimés

aucun

Version Cargo

Conformément à VER-ID-009, cette nouvelle prerelease synchronise la version workspace :

header Cargo.toml : 569 -> 570
workspace.package.version : 0.3.14-pre.2.fix.2 -> 0.3.14-pre.3

Versions des fichiers modifiés :

ksp-onchain-transport-lib/src/lib.rs : 47 -> 48
ksp-onchain-transport-lib/src/ws_protocol_session.rs : 6 -> 7
ksp-onchain-transport-lib/src/ws_session.rs : 14 -> 15
ksp-onchain-transport-lib/tests/public_api.rs : 52 -> 53
ksp-onchain-transport-lib/tests/release_completeness.rs : 44 -> 45
ksp-onchain-transport-lib/unit_tests/ws_session.rs : 11 -> 12
ksp-worker-raw-transaction-ingest-lib/src/continuity.rs : 3 -> 4
ksp-worker-raw-transaction-ingest-lib/src/lib.rs : 28 -> 29
ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs : 29 -> 30
ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs : 26 -> 27
ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs : 21 -> 22
ksp-worker-raw-transaction-ingest-lib/unit_tests/continuity.rs : 2 -> 3
ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs : 23 -> 24

Frontières préservées

aucun repair HTTP
aucun nouveau socket WebSocket
aucun second actor WebSocket
aucun retry Worker
aucune nouvelle dépendance
aucune nouvelle feature
aucun changement Config
aucun changement Store
aucun changement Job Backfill
aucun backend Store physique depuis Worker
aucune mutation Worker de Yellowstone from_slot
aucun SubscribeReplayInfo possédé par Worker
aucun élargissement de la façade publique Worker
src/lib.rs Worker reste exempt de ReplayInfo/from_slot/repair/backfill

Validations exécutées

Dans le sandbox de préparation :

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
scan exact ReplayInfo/from_slot/repair/backfill dans Worker src/lib.rs
scan de possession WebSocket directe dans Worker
scan set_from_slot dans les sources de production Worker
comparaison exacte 0.3.14-pre.002-fix.002 -> 0.3.14-pre.003
contrôle des versions de fichier modifiées
contrôle du contenu de l'archive delta
unzip -t de l'archive delta
réapplication de l'archive sur la base puis comparaison byte-exacte

Validations non exécutées

Le sandbox de préparation ne fournit pas le toolchain Cargo/Rust. Les gates suivants restent donc explicitement à exécuter côté opérateur :

cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p ksp-onchain-transport-lib --all-targets --all-features
cargo test -p ksp-worker-raw-transaction-ingest-lib --all-targets --all-features

Décisions prises

l'observabilité WS réutilise le watch latest-value déjà possédé par Transport
le Worker observe mais ne pilote pas la reconnexion WebSocket
un gap WS commence au dernier slot source réellement observé, inclusivement
le premier slot source post-incident est la borne de fin inclusive
aucune histoire antérieure n'est inventée sans ancre source
le premier événement post-incident est admis avant la terminalité conservative
pre.003 reste fail-closed et ne prétend pas encore réparer le gap

Questions ouvertes

aucune pour pre.003

Tranche suivante

pre.004 reste dédiée à la preuve de replay natif Yellowstone : qualification de SubscribeReplayInfo, preuve de couverture effective et conservation stricte de l'ownership from_slot dans Transport.

Gate opérateur après application

cargo fmt --all
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-onchain-transport-lib --all-targets --all-features
cargo test -p ksp-worker-raw-transaction-ingest-lib --all-targets --all-features