Files
khadhroony-solana-project/docs/plans/016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md
2026-08-24 20:48:30 +02:00

29 KiB
Raw Blame History

Plan 0.2.9 — moteur Yellowstone gRPC + standard Solana + PublicNode

Statut courant : 0.2.9-pre.011 est fermée par gate opérateur complet sans warning. 0.2.9-pre.012 est la tranche active de fermeture technique : réaudit upstream final, smoke PublicNode Mainnet opt-in, compliance finale, graphes Cargo, README/USAGE, règles de tableaux Markdown et prompt autonome 0.2.10 — OrbitFlare Yellowstone gRPC. Les journaux détaillés restent dans deltas/0.2.9/; ce plan conserve létat courant et les décisions.

1. Objet et autorité de la release

Base stable d'ouverture :

v0.2.8

Release :

0.2.9 — Yellowstone gRPC standard/provider-neutral

Le gate pre.001, ses fixes, les deltas techniques suivants et le code réel ont affiné le prompt de démarrage. L'ordre d'autorité utilisé pendant la release est :

règles normatives KSP
code et fichiers réellement livrés
nouveaux deltas immuables de 0.2.9
décisions courantes consolidées dans ce plan et la validation 012
prompt de démarrage pour les contraintes qui n'ont pas été explicitement supersédées

Les deltas historiques ne sont jamais réécrits pour refléter une décision ultérieure.

2. Résultat final attendu

0.2.9 doit fermer une première fondation Yellowstone gRPC exploitable sans devenir un SDK fournisseur :

backend gRPC distinct de HTTP et WebSocket
moteur Tonic/Protobuf privé dans ksp-onchain-transport-lib
façade Yellowstone standard provider-neutral
7 unary standard retenus
Subscribe standard avec les familles/accounts/slots/transactions/blocks retenues
9 variantes SubscribeUpdate courantes
stream bidirectionnel borné
backpressure, half-close et shutdown déterministes
reconnect KSP-owned et replay/from_slot prudent
aucune promesse exactly-once/lossless non prouvée
Config Transport V3 backward-readable V1/V2
provider et protocol distincts dans Config
première intégration PublicNode strictement standard
smoke live opt-in sans credential versionné
non-régressions HTTP, WebSocket standard et Helius WebSocket

3. Scope fermé par pre.001

3.1 Inclus

N1 — moteur Yellowstone gRPC
N2 — standard Solana Yellowstone
N3 — première intégration PublicNode quand elle réutilise le standard sans divergence wire
TLS et metadata provider-neutral
7 unary standards retenus
Subscribe standard retenu
reconnect/replay observables mais non lossless
Config V3 si le mapping reste Config -> Transport
smokes PublicNode architecture-safe

3.2 Hors scope 0.2.9

SubscribeDeshred / pré-exécution
extensions Triton spécifiques
adapter Helius LaserStream gRPC spécifique
adapter OrbitFlare spécifique
pool/scheduler automatique complexe de sessions gRPC
serveur Geyser/plugin validator
Store/persistence/backfill historique
workers/jobs d'acquisition
replay lossless garanti
refonte HTTP ou WebSocket

Les intégrations provider futures ne dupliquent jamais le moteur N1. Une façade provider n'existe que si elle porte une divergence réelle : auth, capabilities, restriction, extension wire ou policy lifecycle.

4. Audit upstream et dépendances retenues

4.1 Snapshot normatif et réaudit final

Le gate d'ouverture puis le réaudit final du 2026-08-24 confirment que les numéros du plugin, du client, du proto et des releases GitHub évoluent indépendamment. Il ne faut donc pas transformer un numéro de master en numéro de release publié.

État observé au réaudit final :

latest release GitHub indexée         v14.2.2+solana.4.1.0 — 2026-07-27
master yellowstone-grpc-geyser        15.1.2
master yellowstone-grpc-client        13.3.0
master yellowstone-grpc-proto         12.6.0
master Agave Geyser / storage         4.2.0
master prost / prost-types / tonic    0.14.x
KSP yellowstone-grpc-proto direct     ^12.6

Le service Geyser, la shape de SubscribeRequest et les neuf variantes SubscribeUpdate retenues par KSP n'ont pas changé matériellement par rapport au gate pre.001. SubscribeDeshred reste explicitement hors scope 0.2.9.

Les sources primaires restent :

https://github.com/rpcpool/yellowstone-grpc/releases
https://github.com/rpcpool/yellowstone-grpc/blob/master/CHANGELOG.md
https://github.com/rpcpool/yellowstone-grpc/blob/master/yellowstone-grpc-proto/proto/geyser.proto
https://github.com/rpcpool/yellowstone-grpc/blob/master/yellowstone-grpc-proto/proto/solana-storage.proto
https://github.com/rpcpool/yellowstone-grpc/blob/master/LICENSING.md
https://docs.rs/crate/yellowstone-grpc-proto/latest
https://docs.rs/crate/yellowstone-grpc-client/latest

Une réaudite finale est requise en pre.012 si l'upstream a changé matériellement pendant la release.

4.2 Licence

Le repository upstream est globalement AGPL-3.0-only, mais LICENSING.md affecte explicitement Apache-2.0 à :

examples/
yellowstone-grpc-client/
yellowstone-grpc-client-nodejs/
yellowstone-grpc-proto/

Décision :

dépendance publiée yellowstone-grpc-proto = acceptée
.proto vendored dans KSP                      = non
source provenant des zones AGPL              = non copiée
future copie upstream                         = nouveau gate provenance/licence obligatoire

4.3 Stratégie client

Stratégie Décision Raison principale
yellowstone-grpc-client + yellowstone-grpc-proto non retenue importerait trop de lifecycle/reconnect upstream et de surface client
yellowstone-grpc-proto + client KSP autour de tonic retenue wire officiel, moteur/lifecycle/redaction KSP-owned
proto/génération KSP vendored fallback seulement dette licence/synchronisation/build plus forte

Matérialisation courante :

yellowstone-grpc-proto ^12.6   runtime sans feature tonic
yellowstone-grpc-proto         dev/test avec feature tonic pour GeyserServer fixture
tonic ^0.14                    channel + TLS runtime ; codegen/server dev/test
tonic-prost ^0.14              ProstCodec bas niveau
http ^1.5                      PathAndQuery interne
yellowstone-grpc-client        absent
prost/prost-types              aucune dépendance KSP directe
proto vendored                 absent

Les graphes Cargo inspectés pendant pre.002/pre.003 n'ont pas révélé de seconde génération incompatible à corriger. Le graph final est réinspecté en pre.012.

5. Matrice protocolaire fermée

5.1 Service Geyser

RPC Forme Classification Cible 0.2.9 État
Subscribe bidi stream standard Yellowstone oui DONE pre.009/pre.010
SubscribeDeshred bidi stream extension/pré-exécution Triton publiée dans le proto non OUT
SubscribeReplayInfo unary standard oui DONE
Ping unary standard oui DONE
GetLatestBlockhash unary standard oui DONE
GetBlockHeight unary standard oui DONE
GetSlot unary standard oui DONE
IsBlockhashValid unary standard oui DONE
GetVersion unary standard oui DONE

SubscribeDeshred reste explicitement exclu même s'il existe dans le proto publié : sa présence wire n'en fait pas une capacité provider-neutral de la fondation KSP.

5.2 SubscribeRequest

Champ Sémantique État
accounts map nom -> filtre accounts DONE
slots map nom -> filtre slots DONE
transactions map nom -> filtre transactions DONE
transactions_status même famille de filtre transaction DONE
blocks map nom -> filtre blocks DONE
blocks_meta map nom -> filtre marqueur vide DONE
entry map nom -> filtre marqueur vide DONE
commitment optional Processed/Confirmed/Finalized DONE
accounts_data_slice repeated offset/length DONE
ping optional request ping/id DONE
from_slot optional u64 DONE, sémantique prudente

Accounts :

account[]
owner[]
filters[]
nonempty_txn_signature?
cuckoo_accounts_filter?

memcmp { offset, oneof bytes | base58 | base64 }
datasize
token_account_state
lamports { oneof eq | ne | lt | gt }

Slots :

filter_by_commitment?
interslot_updates?
statuses = processed | confirmed | finalized | first_shred_received | completed | created_bank | dead

Transactions et transaction_status :

vote?
failed?
signature?
account_include[]
account_exclude[]
account_required[]
cuckoo_account_include?
token_accounts? = ALL | BALANCE_CHANGED

Blocks :

account_include[]
include_transactions?
include_accounts?
include_entries?
cuckoo_account_include?

blocks_meta et entry conservent la distinction absence / map vide / filtre nommé vide.

Bornes KSP communes matérialisées :

filter groups nommés total     <= 1024
filter name                    1..128 octets, trim exact, sans contrôle
filter names                   uniques globalement entre les sept maps
accounts_data_slice count      <= 128
accounts_data_slice length     <= 64 MiB
offset + length                sans overflow u64

Les bounds spécifiques Accounts/Transactions/Blocks sont ceux désormais testés dans leurs tranches respectives ; ils ne sont pas dupliqués comme knobs Config.

5.3 SubscribeUpdate

Variante Champs structurants conservés État
account account info + slot + is_startup DONE
slot slot + parent? + status + dead_error? DONE
transaction signature/is_vote/transaction/meta/index + slot DONE
transaction_status slot/signature/is_vote/index/error DONE
block slot/hash/rewards/time/height/parent/counts + transactions/accounts/entries DONE
ping marker server ping DONE
pong id DONE
block_meta block metadata/counts sans tableaux complets DONE
entry slot/index/num_hashes/hash/transaction counts/index DONE

Le top-level conserve également filters[] et created_at. Les types Prost/Yellowstone générés restent privés.

5.4 Unary standards

RPC Request Response KSP utile État
SubscribeReplayInfo vide first_available? DONE
Ping count count DONE
GetLatestBlockhash commitment? slot, blockhash, last_valid_block_height DONE
GetBlockHeight commitment? block_height DONE
GetSlot commitment? slot DONE
IsBlockhashValid blockhash + commitment? slot + valid DONE
GetVersion vide version bornée DONE

Ces capacités ne remplacent pas les wrappers Solana JSON-RPC HTTP.

6. Architecture runtime actuelle

6.1 Séparation des backends

HTTP                         HttpTransportSettings / pool HTTP
WebSocket engine             WsSession actor partagé
Solana standard WS           SolanaStandardWsSession
Helius LaserStream WS        HeliusLaserStreamWsSession

Yellowstone gRPC engine      YellowstoneGrpcChannel + moteur bidi KSP
Solana Yellowstone standard  contrats typed KSP
provider                     descripteur d'exécution/capability, pas nouveau protocole

Interdictions :

pas de WsProtocolKind pour gRPC
pas de WsEndpointSettings pour gRPC
pas de client Tonic brut réexporté
pas de second moteur physique par provider
pas de façade provider vide qui ne ferait que renommer le standard

6.2 Contrats publics principaux matérialisés

YellowstoneGrpcEndpointUrl
YellowstoneGrpcProviderName
YellowstoneGrpcClusterName
YellowstoneGrpcMetadataEntry
YellowstoneGrpcReconnectSettings
YellowstoneGrpcSessionSettings
YellowstoneGrpcEndpointSettings
YellowstoneGrpcTransportSettings
YellowstoneGrpcChannel

YellowstoneSubscribeRequest + filtres typed
YellowstoneSubscribeUpdate + variantes typed
SolanaYellowstoneGrpcSubscribeSession
YellowstoneGrpcSubscribeSnapshot
7 unary typed

Le wire Tonic/Prost reste privé et n'est pas une escape hatch publique.

6.3 Credentials et diagnostics

Transport reçoit des valeurs déjà résolues par son consumer. Il ne connaît :

aucun KSP_SECRET_*
aucun KSP_PUBLIC_*
aucun std::env
aucun header commercial hardcodé dans le standard

Les URLs, metadata sensibles, messages/details de tonic::Status et payloads arbitraires ne sont pas recopiés dans Debug, Display, snapshots ou contexts KSP.

7. Lifecycle, backpressure et continuité

7.1 Stream bidi

Acquis depuis pre.009 :

une request mpsc bornée consommée par Tonic
une update queue bornée côté KSP
mutation du SubscribeRequest sur le même stream
Ping serveur -> réponse automatique appropriée
Pong décodé
server half-close observable
client explicit close borné
Drop best-effort sans panic
oversized inbound/outbound borné
slow receiver overflow terminal et observable
shutdown déterministe

Aucune queue non bornée et aucun drop silencieux n'est présenté comme lossless.

7.2 Reconnect/replay

Acquis depuis pre.010 :

reconnect automatique           oui, borné et KSP-owned
resubscribe                     dernier SubscribeRequest complet accepté
from_slot de reprise            max(from_slot explicite, dernier slot observé) quand applicable
SubscribeReplayInfo             informatif
first_available                 clamp/prouve un gap seulement s'il dépasse le slot demandé
exactly-once                    non garanti
lossless                        non garanti
ordre global sans gap           non garanti
duplicate                       possible, compté, non supprimé silencieusement
gap                             compté seulement lorsqu'une preuve est disponible
shutdown during backoff         interrompt la reconnexion
budget reconnect épuisé         état terminal safe

Snapshot public safe :

reconnect_count
replay_attempt_count
continuity_gap_count
duplicate_update_count
last_requested_from_slot
last_observed_slot
terminal state/error code safe

La présence de from_slot ou SubscribeReplayInfo n'autorise aucune promesse de replay historique complet.

8. Config Transport V3 — tranche pre.011

8.1 Compatibilité documentaire

Décision fermée :

V1 = HTTP-only, backward-readable
V2 = HTTP + WebSocket, backward-readable
V3 = HTTP + WebSocket + Yellowstone gRPC optionnel par profil

Le schema V3 conserve des branches strictes V1/V2 au lieu de relâcher leurs additionalProperties.

Shape V3 :

format_version = 3
retry
ws_defaults
grpc_defaults
default_profile
profiles[] {
    profile_id
    endpoints[]
    ws_endpoints[]
    grpc_endpoints[]?   # optionnel par profil
}

L'absence de grpc_endpoints dans un profil V3 signifie None, pas un YellowstoneGrpcTransportSettings vide inventé.

8.2 grpc_defaults

Les defaults Config correspondent uniquement à de vrais settings runtime Transport :

connect_timeout_ms
unary_timeout_ms
close_timeout_ms
reconnect.max_retries
reconnect.initial_backoff_ms
reconnect.max_backoff_ms
request_channel_capacity
update_channel_capacity
max_inbound_message_size_bytes
max_outbound_message_size_bytes

Les bounds de filtres Subscribe restent un contrat Transport fixe et ne deviennent pas des options Config sans besoin démontré.

8.3 Endpoint gRPC

Chaque grpc_endpoints[] porte :

name
enabled
provider
cluster
protocol = solana_yellowstone
url
metadata[]?          # classe publique
secret_metadata[]?   # classe secrète
session?             # overrides bornés

Axes distincts :

protocol  = contrat wire standard, actuellement solana_yellowstone
provider  = environnement d'exécution descriptif, par exemple publicnode

provider = publicnode ne crée donc pas un PublicNodeGrpcProtocol ni une façade provider sans divergence réelle.

8.4 Provenance des metadata

Config est propriétaire de la résolution :

metadata          -> interdit toute provenance KSP_SECRET_*/KSPB_SECRET_*
secret_metadata   -> exige au moins une provenance secret et interdit une variable non-secret
littéraux autour d'un placeholder secret -> autorisés ; safe_value masque seulement le segment secret

Transport reçoit ensuite YellowstoneGrpcMetadataEntry public/secret et ne connaît jamais le nom de variable d'environnement.

8.5 API Config sans rupture V2

L'API existante reste :

http_settings()
ws_settings()
into_transport_settings() -> (HTTP, Option<WS>)

pre.011 ajoute :

grpc_settings()
into_all_transport_settings() -> (HTTP, Option<WS>, Option<Yellowstone gRPC>)

Le tuple historique n'est pas modifié silencieusement.

9. PublicNode dans 0.2.9

9.1 Mainnet

La surface publique réauditée le 2026-08-24 confirme Yellowstone gRPC Solana Mainnet et affiche le host/port :

solana-yellowstone-grpc.publicnode.com:443

Le wrapper KSP attend une URL http/https; Config matérialise donc le même endpoint TLS sous la forme https://solana-yellowstone-grpc.publicnode.com:443.

pre.011 versionne donc un profil :

profile_id = publicnode_mainnet
provider   = publicnode
cluster    = mainnet-beta
protocol   = solana_yellowstone
credential = aucun

La partie HTTP/WS de ce profil reste standard Solana ; seul l'endpoint gRPC est PublicNode.

9.2 Testnet

Le réaudit final du 2026-08-24 confirme que PublicNode annonce bien une capacité Solana Testnet gRPC. La surface officielle consultable ne fournit cependant toujours pas un hostname Testnet exact suffisamment autoritatif pour être versionné.

Décision finale 0.2.9 :

existence Testnet gRPC          confirmée
hostname Testnet exact          non obtenu depuis une source autoritative
hostname déduit ou tiers        interdit
profil Testnet committé         non
smoke Testnet                   non
statut                          EXTERNAL BLOCK documentaire / NOT GUESSED

Ce bloc externe ne remet pas en cause la fondation Mainnet. Une release provider ultérieure peut matérialiser Testnet dès qu'une source PublicNode autoritative expose l'endpoint exact.

10. Threat model et bornes

Menaces couvertes :

credential dans URI/metadata
Status/message/details provider arbitraires
Debug dérivé de filtres/payloads
TLS/connect error qui réémet l'URI
message inbound/outbound hostile
stream flood / slow consumer
filter explosion / collision de noms
unknown enum/oneof
server/client half-close
reconnect loop
node divergent après reconnect
duplicate/gap après replay
mutation tardive du stream

Réponses :

wrappers redacted
allowlist de contexts KSP
validation/bounds avant I/O
queues bornées
états terminaux observables
reconnect budget borné
aucune promesse de continuité non prouvée
Config sensitivity gate avant construction de metadata secret

11. Smoke ownership

Ordre de preuve :

Transport programmatic -> PublicNode Mainnet Yellowstone
Transport programmatic -> PublicNode Testnet seulement si endpoint exact confirmé
Config V3 -> Transport -> PublicNode via composition légitime, jamais un smoke réseau placé dans Config par facilité

Un smoke Transport pur peut vivre dans ksp-onchain-transport-lib/tests puisqu'il construit ses settings programmatiquement.

Un smoke cross-crates Config -> Transport ne doit pas devenir une responsabilité durable de ksp-config-lib. S'il n'existe pas encore de surface d'intégration appropriée, la procédure reste opérateur/documentée en pre.012.

Aucun secret provider n'est versionné.

12. État des tranches et historique compact

Les preuves détaillées restent dans les fichiers deltas/0.2.9/*.md. Le plan ne duplique plus leurs journaux complets.

Tranche Objet État consolidé
pre.001 + fixes audit upstream, licence, providers, architecture, sizing CLOSED
pre.002 + fixes dépendances, settings/errors, channel minimal CLOSED
pre.003 + fix TLS, metadata, fixture locale, 7 unary CLOSED
pre.004 + fix Subscribe foundation/common CLOSED
pre.005 + fix Accounts + Slots CLOSED
pre.006 namespace privé HTTP explicite CLOSED
pre.007 Transactions + transaction_status CLOSED
pre.008 + fix Blocks + block_meta + entry CLOSED
pre.009 + fix bidi, Ping/Pong, backpressure, half-close, shutdown CLOSED
pre.010 + fix reconnect, from_slot, ReplayInfo, gaps/duplicates CLOSED
pre.011 Config V3 + protocol/provider + PublicNode Mainnet CLOSED
pre.012 live/compliance/docs/graph/prompt suivant ACTIVE CANDIDATE

Gate opérateur de fermeture pre.011 :

fmt/audit/check/clippy       PASS sans warning
Config unit                 113/113
Config public API           15/15
Config ownership            5/5
Transport unit              383/383
Transport public API        49/49
Transport completeness      43/43
Transport doctests          4/4
workspace dependencies      3/3
cargo test --workspace      PASS

13. Forecast restant

pre.012 — fermeture technique et live

Cible active :

workspace.package.version = 0.2.9-pre.12
réaudit upstream final
réaudit PublicNode Testnet sans endpoint inventé
smoke PublicNode Mainnet opt-in, programmatique et sans credential
compliance HTTP 52 current + 14 historical
compliance Standard WS 18/18
Helius WebSocket non régressé
cargo tree direct + duplicates final
README/USAGE Transport synchronisés
règles Markdown sur les tableaux reformulées et auditées mécaniquement
validation 012 fermée si les gates opérateur sont verts
prompt 0.2.10 OrbitFlare autonome
workspace final vert

La candidate ajoute un smoke live ignoré par défaut ; elle ne modifie pas le runtime Yellowstone déjà fermé. Le smoke Mainnet utilise uniquement la façade provider-neutral KSP, GetVersion et GetSlot, avec TLS et sans metadata d'authentification.

Le Testnet reste EXTERNAL BLOCK / NOT GUESSED tant que PublicNode n'expose pas l'endpoint exact dans une source autoritative.

Si le gate opérateur révèle une anomalie réelle, un pre.012-fix.001 est créé. Si la fermeture nécessite une nouvelle frontière fonctionnelle plutôt qu'un fix, une pre.013+ est ouverte ; le numéro n'est pas une deadline.

14. Critères de split

Scinder avant dette silencieuse si :

  1. une évolution upstream matérielle invalide le wire retenu ;
  2. PublicNode exige une divergence provider-specific significative ;
  3. le replay nécessite un sous-système de fork/equivocation plus large que la foundation ;
  4. une tranche dépasse nettement le budget nominal sans frontière claire ;
  5. le gate final montre une dette dépendance/licence ou une non-régression qui ne peut pas être corrigée proprement dans la tranche.

Le noyau à préserver reste :

moteur Yellowstone + façade Solana standard + Config provider-neutral + première intégration PublicNode minimale

15. Gates opérateur

Gate pre.012 :

cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.9
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-config-lib
cargo test -p ksp-onchain-transport-lib
cargo test -p ksp-core-lib --test workspace_dependencies
cargo test --workspace

Graphes finaux :

cargo tree -p ksp-onchain-transport-lib
cargo tree -p ksp-onchain-transport-lib --duplicates
cargo tree --duplicates

Smoke live opt-in Mainnet :

cargo test -p ksp-onchain-transport-lib --test yellowstone_publicnode_smoke -- --ignored --nocapture

Le smoke n'est jamais déclaré réussi avant exécution. Un incident externe PublicNode/TLS/réseau est consigné comme tel et ne doit pas être maquillé en PASS local. Le Testnet n'est pas exécuté tant que son endpoint exact n'est pas confirmé par une source PublicNode autoritative.

16. Conditions de clôture 0.2.9

service/proto courant réconcilié
SubscribeDeshred explicitement OUT
7 unary verts
Subscribe standard et 9 updates verts
backend gRPC distinct de HTTP/WS
raw Tonic/Prost privé
secrets/metadata redacted
bounds/backpressure/shutdown verts
reconnect/replay documentés sans lossless implicite
Config V3 backward V1/V2
provider/protocol distincts
PublicNode Mainnet validé
Testnet validé si endpoint exact confirmé, sinon report factuel documenté
HTTP 52+14 non régressé
Standard WS 18/18 non régressé
Helius WS non régressé
cargo graphs finaux inspectés
README/USAGE finaux synchronisés
validation 012 fermée
prompt release suivante prêt
workspace final vert

17. Séquence après 0.2.9

La séquence active a été recalibrée par les fixes de pre.001; cette décision est conservée pendant le nettoyage documentaire :

0.2.9   moteur Yellowstone + Solana standard + PublicNode
0.2.10  OrbitFlare Yellowstone gRPC
0.2.11  Helius LaserStream gRPC
0.2.12  off-chain price transport
0.2.13  Price Desk + intégration prix Wallet Desk
0.2.14  interface/wire foundation
0.2.15  program-api foundation

Les intégrations suivantes restent dans le backlog non numéroté tant qu'aucune décision d'implémentation ne les fait entrer dans la séquence active :

TODO   eRPC
TODO   Triton
TODO   Alchemy
TODO   QuickNode
TODO   Chainstack
IDEAS  Tatum
IDEAS  Shyft
IDEAS  Solinfra
IDEAS  NodeFlare

OrbitFlare reste le provider dédié 0.2.10 et Helius LaserStream gRPC 0.2.11 selon la séquence recalibrée par les fixes de pre.001. Chaque release doit réauditer auth, capabilities, restrictions, extensions wire, replay/from_slot et lifecycle au lieu de supposer une équivalence complète avec N2.