Files
2026-09-11 22:22:51 +02:00

12 KiB

Delta 0.3.14-pre.004 — preuve conservative de replay natif Yellowstone

Base requise

0.3.14-pre.003
workspace.package.version = 0.3.14-pre.3
deltas/0.3.14/pre.003.md présent

Gate de la base

Le gate opérateur de 0.3.14-pre.003 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-onchain-transport-lib --all-targets --all-features : PASS
cargo test -p ksp-worker-raw-transaction-ingest-lib --all-targets --all-features : PASS

Le gate Transport comprend notamment :

390 unit tests : PASS
public_api : 53 PASS
release_completeness : 45 PASS
smokes live : ignorés par défaut conformément au contrat existant

Le gate Worker comprend notamment :

119 unit tests : PASS
cross_layer_completeness : 8 PASS
dependency_boundary : 19 PASS
hardening : 28 PASS
public_api : 20 PASS
release_completeness : 5 PASS

Objectif

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

conserver l'ownership Yellowstone from_slot / SubscribeReplayInfo dans Transport
distinguer replay attempt de replay delivery
distinguer toute delivery ponctuelle d'une preuve de coverage
conserver first_available comme preuve de limite de rétention uniquement
rendre observable une reprise acceptée dont la couverture reste non prouvée
rester fail-closed côté Worker tant que les tranches de réconciliation ne sont pas présentes
ne créer aucun replay Worker, aucun repair HTTP et aucune nouvelle source

Transport — distinction attempt / delivery / coverage non prouvée

YellowstoneGrpcSubscribeSnapshot conserve replay_attempt_count et ajoute deux compteurs sûrs :

replay_delivery_count
replay_coverage_unproven_count

La sémantique est volontairement conservative.

replay_delivery_count n'augmente que lorsqu'une reconnexion replay-bearing redélivre exactement le slot de reprise effectivement demandé par Transport. Cette observation prouve uniquement qu'un matériau slot-bearing a été livré au bord demandé. Elle ne prouve pas que tous les updates correspondant aux filtres ont été rejoués sur l'intervalle.

replay_coverage_unproven_count augmente lorsqu'une reconnexion replay-bearing a réussi et que :

le premier update slot-bearing post-reconnect atteint ou dépasse la borne demandée
ou
un nouveau reconnect commence avant tout matériau slot-bearing replayé

Même une redélivrance exacte de la borne fait donc progresser replay_delivery_count et replay_coverage_unproven_count : la première prouve une delivery ponctuelle, la seconde conserve explicitement l'absence de preuve de couverture complète.

Cette valeur signifie explicitement coverage non prouvée. Elle ne prouve pas qu'un événement filtré existait, qu'il a été perdu, ni que le provider a nécessairement violé son contrat.

Aucun compteur générique replay_covered / replay_coverage_proven n'est ajouté. Le replay natif Transport ne possède pas aujourd'hui une preuve générique suffisante pour faire cette affirmation.

Transport — tracker de replay

Le ContinuityTracker existant conserve maintenant une seule borne privée :

pending_replay_from_slot

Lorsqu'un reconnect physique Yellowstone réussit avec un effective_from_slot, Transport ouvre cette preuve pending.

Sur le premier update slot-bearing :

slot == requested -> delivery conservatrice prouvée + coverage globale toujours non prouvée
slot > requested  -> aucune delivery de borne prouvée + coverage globale non prouvée
slot < requested  -> aucune conclusion positive ; la preuve reste pending

Si le stream se coupe de nouveau avant résolution de la borne pending, la coverage de cette tentative est classée non prouvée avant d'ouvrir la tentative suivante.

Les Ping/Pong ne ferment jamais cette preuve parce qu'ils ne portent aucun slot.

Transport — rétention SubscribeReplayInfo

Le contrat antérieur reste inchangé :

first_available > requested

incrémente continuity_gap_count, clamp le from_slot effectif dans Transport et signifie uniquement que l'endpoint ne peut pas rejouer avant first_available.

Le clamp ne devient pas une preuve de perte d'un événement filtré et ne devient pas une preuve de coverage complète.

Cas replay accepté mais couverture non prouvée

Une fixture dédiée couvre le cas adversarial prévu au plan :

avant coupure : slot 800 observé
reconnect : from_slot = 800 accepté
premier update après reconnect : slot 805

Résultat attendu :

reconnect_count = 1
replay_attempt_count = 1
replay_delivery_count = 0
replay_coverage_unproven_count = 1
continuity_gap_count = 0

Le résultat ne prétend ni qu'un update manquait réellement entre 800 et 805, ni que le replay est complet. Il démontre seulement que KSP ne possède pas la preuve conservative de delivery requise pour assimiler la reprise à une couverture saine.

La fixture de replay redélivrant slot 500 conserve au contraire :

replay_attempt_count = 1
replay_delivery_count = 1
replay_coverage_unproven_count = 1

Cette delivery ne devient toujours pas un replay_covered.

Worker — consommation des preuves Transport

RawTransactionIngestProcessingFrontierReporter observe désormais de manière monotone :

replay_attempt_total
replay_delivery_total
replay_coverage_unproven_total
continuity_gap_total

Le Worker ne calcule aucun from_slot, n'appelle jamais SubscribeReplayInfo et ne construit aucune requête replay.

La phase replay_attempt peut être observée avant toute delivery et ne ferme aucune obligation de coverage. Une delivery de borne fait ensuite progresser la preuve de delivery mais conserve simultanément coverage_unproven.

Une progression de replay_coverage_unproven_total sans gap de rétention produit actuellement :

source.replay_coverage_unproven

et conserve la terminalité fail-closed de la source. Cette terminalité est volontairement temporaire jusqu'aux tranches de coverage redondante et de réconciliation du plan 035 ; elle évite qu'un replay accepté mais non prouvé soit assimilé silencieusement à une continuité saine.

Si continuity_gap_total augmente simultanément, la preuve de rétention plus forte conserve la priorité et produit le contrat existant :

source.continuity_gap_proven

Les nouveaux compteurs privés sont soumis au même rejet de régression que les compteurs reconnect/replay existants.

Surface publique

Transport étend uniquement le snapshot Yellowstone déjà public avec :

YellowstoneGrpcSubscribeSnapshot::replay_delivery_count()
YellowstoneGrpcSubscribeSnapshot::replay_coverage_unproven_count()

Aucun type provider, payload, endpoint, credential ou proto upstream n'est exposé.

La façade publique Worker n'est pas étendue. Les preuves supplémentaires restent privées au runtime Worker dans cette tranche.

Documentation d'utilisation

ksp-onchain-transport-lib/USAGE.md explicite désormais que :

attempt != delivery != coverage
une delivery ponctuelle n'est pas une preuve de replay_covered
coverage_unproven est une absence explicite de preuve, pas une preuve de perte

Le document reste version-neutral conformément aux règles workspace.

Tests ajoutés/étendus

Transport couvre :

replay avec redélivrance exacte de la borne -> delivery = 1
rétention first_available -> gap = 1 tout en conservant delivery distincte
reconnects exhaustés -> attempts sans fausse delivery
replay accepté puis progression au-delà de la borne -> coverage_unproven = 1
absence de compteur générique replay_covered/replay_coverage_proven
accessibilité crate-root des deux getters snapshot

Worker couvre :

attempt seul != delivery
delivery de borne != coverage
coverage_unproven devient fail-closed
régression delivery/coverage_unproven rejetée
absence persistante de set_from_slot / SubscribeReplayInfo / YellowstoneReplayInfo dans Worker

Fichiers ajoutés

deltas/0.3.14/pre.004.md

Fichiers modifiés

Cargo.toml
crates/ksp-onchain-transport-lib/USAGE.md
crates/ksp-onchain-transport-lib/src/grpc_stream.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/grpc_stream.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/runtime_resources.rs

Fichiers supprimés

aucun

Version Cargo

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

header Cargo.toml : 570 -> 571
workspace.package.version : 0.3.14-pre.3 -> 0.3.14-pre.4

Versions des fichiers modifiés :

ksp-onchain-transport-lib/USAGE.md : 25 -> 26
ksp-onchain-transport-lib/src/grpc_stream.rs : 4 -> 5
ksp-onchain-transport-lib/tests/public_api.rs : 53 -> 54
ksp-onchain-transport-lib/tests/release_completeness.rs : 45 -> 46
ksp-onchain-transport-lib/unit_tests/grpc_stream.rs : 5 -> 6
ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs : 30 -> 31
ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs : 27 -> 28
ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs : 22 -> 23
ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs : 24 -> 25

Frontières préservées

from_slot reste Transport-owned
SubscribeReplayInfo reste Transport-owned
aucun set_from_slot dans Worker
aucun replay loop Worker
aucun retry réseau Worker
aucun repair HTTP
aucune nouvelle source
aucun nouveau provider
aucune nouvelle dépendance
aucune nouvelle feature
aucun changement Config
aucun changement Store
aucun changement Job Backfill
aucun backend Store physique depuis Worker
aucun replay_covered générique inventé par Transport
aucun élargissement de la façade publique Worker

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 de possession replay dans Worker
scan des nouveaux compteurs attempt/delivery/coverage_unproven
comparaison exacte 0.3.14-pre.003 -> 0.3.14-pre.004
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

replay attempt ne prouve aucune delivery
delivery au slot demandé ne prouve aucune coverage complète
absence de delivery conservative avant progression/reconnect suivant devient coverage_unproven
first_available reste une preuve de rétention et non une preuve d'événement perdu
aucun replay_covered n'est revendiqué par Transport générique
le Worker reste fail-closed sur coverage_unproven jusqu'aux tranches de réconciliation

Questions ouvertes

aucune pour pre.004

Tranche suivante

pre.005 reste dédiée à la coverage redondante : relations exact/superset conservatrices, epochs/ranges de coverage et refus explicite des équivalences cross-family opportunistes.

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