Files
khadhroony-solana-project/docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
2026-08-31 13:07:56 +02:00

50 KiB

Plan 0.3.5 — Interface passive acquisition events

1. Statut de la release

Base canonique auditée :

v0.3.4
workspace.package.version = 0.3.4

Version de travail à la réconciliation documentaire finale :

workspace.package.version = 0.3.5-pre.7
label = 0.3.5-pre.007

La release est fonctionnellement fermée. pre.001 a ouvert l'audit ; son fix a établi l'intersection exacte de sept stages slot et rouvert le candidat transaction execution. pre.002 a matérialisé SlotLifecycleEvent, pre.003 a admis TransactionExecutionEvent, pre.004/pre.005 ont fermé les canaris de complétude et le hardening, puis pre.006 a validé le gate workspace et le graphe Cargo final.

pre.007 ne modifie aucun contrat Rust. Elle réconcilie les documents durables avec la surface réellement acquise et transfère l'idée TransactionLogEvent vers docs/IDEAS.md au lieu de laisser un TODO caché dans le plan de release.

2. Mission

La release doit étendre ksp-interface-lib seulement lorsqu'un consumer de composition peut recevoir un fait passif KSP-owned sans dépendre du protocole producteur et sans créer un second modèle RAW.

Le contrat cible reste :

producer Transport
    -> DTO Transport riche et lossless
    -> conversion explicite à la composition
    -> fait Interface passif minimal, seulement si la sémantique commune est prouvée

Le type Interface ne remplace jamais le DTO Transport. Les informations source-specific qui ne font pas partie du fait commun restent disponibles sur le DTO Transport et ne sont pas copiées dans Interface.

3. Sources relues

3.1 Sources internes

Le gate a relu les familles prescrites par le prompt :

RULES.md
docs/000-README.md

docs/rules/RULES_GENERAL.md
docs/rules/RULES_KSP.md
docs/rules/RULES_RUST.md
docs/rules/RULES_DEPENDENCIES.md
docs/rules/RULES_DOCUMENTATION.md
docs/rules/FILE_CONTRACTS.md
docs/rules/VERSION_WORKFLOW.md
docs/rules/PROMPT_STRUCTURE.md

docs/architecture/000-README.md
docs/architecture/001-PROJECT_OBJECTIVES.md
docs/architecture/002-LAYERS_AND_DEPENDENCIES.md
docs/architecture/003-COMPONENT_CONTRACTS.md
docs/architecture/004-COMPONENT_INVENTORY.md
docs/architecture/005-DEPENDENCY_GRAPH.md
docs/architecture/006-WIRE_AND_PROGRAM.md
docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
docs/architecture/010-APPS_SERVICES_SCENARIOS_AND_CONTROL.md

docs/plans/020-V0_2_13_INTERFACE_PLAN.md
docs/validation/016-V0_2_13_INTERFACE.md
docs/plans/022-V0_3_1_STORE_RAW_PLAN.md
docs/validation/018-V0_3_1_STORE_RAW.md
docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md
docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md
docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md
docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md
docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md
docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md

Les sources Rust relues couvrent ksp-interface-lib, ksp-store-api, la façade/backend Store et les modules HTTP/WS/gRPC/Helius event-like de ksp-onchain-transport-lib demandés par le prompt.

3.2 Surface Interface/Store stable constatée

Inventaire crate-root actuel de ksp-interface-lib :

Pubkey
ProgramAccountMeta
ProgramInstruction
MAX_PROGRAM_INSTRUCTION_ACCOUNTS
MAX_PROGRAM_INSTRUCTION_DATA_LEN
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED

Modules de production actuels :

error
program_account_meta
program_instruction

Le manifeste Interface ne possède qu'une dependency normale :

ksp-core-lib

Le consumer runtime/public actuel identifié est ksp-program-api, qui réutilise ProgramAccountMeta et ProgramInstruction. Aucun consumer actuel n'impose encore un event d'acquisition.

La surface Store stable expose exactement dix capabilities RAW :

RawTransactionRead
RawTransactionWrite
RawTransactionObservationRead
RawTransactionObservationWrite
RawTransactionRetentionRead
RawTransactionRetentionWrite
RawAccountStateRead
RawAccountStateWrite
RawAccountObservationRead
RawAccountObservationWrite

3.3 Sources externes courantes auditées le 2026-08-31

L'audit externe a porté sur les documents normatifs/courants suivants :

Solana RPC WebSocket:
- slotSubscribe
- slotsUpdatesSubscribe
- rootSubscribe / index WebSocket
- signatureSubscribe
- logsSubscribe
- voteSubscribe
- accountSubscribe
- programSubscribe

Solana RPC HTTP:
- getSignatureStatuses
- getTransaction
- getBlock

Yellowstone gRPC upstream et version KSP :
- KSP stable déclare `yellowstone-grpc-proto = ^12.6`
- geyser.proto / SlotStatus / SubscribeUpdateSlot
- transaction_status
- account / transaction / block / block_meta / entry update families
- upstream courant comparé pour vérifier que l'intersection SlotStatus retenue n'est pas une hypothèse obsolète

Helius:
- LaserStream-powered standard WebSockets
- Enhanced WebSocket transactionSubscribe

Les conclusions externes qui structurent le plan sont :

  • slotSubscribe signale le traitement d'un nouveau slot et transporte slot, parent et le root courant ;
  • slotsUpdatesSubscribe est instable et publie firstShredReceived, completed, createdBank, frozen, dead, optimisticConfirmation et root, avec metadata conditionnelle ;
  • Yellowstone expose Processed, Confirmed, Finalized, FirstShredReceived, Completed, CreatedBank et Dead ;
  • signatureSubscribe est un abonnement one-shot à une signature, éventuellement précédé de receivedSignature, et n'est pas un snapshot HTTP ;
  • getSignatureStatuses reste un snapshot queryable avec confirmations/status/confirmationStatus ;
  • voteSubscribe publie des votes gossip pré-consensus, sans garantie qu'ils entrent dans le ledger ;
  • Helius conserve les méthodes standard Solana et possède en plus des extensions Enhanced WebSocket, notamment transactionSubscribe, qui restent provider-specific.

4. Invariants d'ownership

Les règles directement structurantes restent :

KSP-TRANSPORT-002..004
KSP-STORE-001..002
KSP-NOTIFY-001..006
KSP-PROC-007..008
KSP-REL-005..016
DEP-KSP-*
DEP-LOG-*
DEP-STORE-*
DEP-WORKER-*
DEP-JOB-*

Le graphe cible reste :

ksp-interface-lib
└── ksp-core-lib

Et les frontières restent :

Interface -X-> Transport
Interface -X-> Store API / Store
Interface -X-> Program API / Program Lib
Interface -X-> Config / Wallet
Transport -X-> Store API
Store API -X-> Transport
composition supérieure = owner des conversions

ksp-program-api reste un consumer de la surface Program-facing existante de ksp-interface-lib. Il n'a aucune raison de re-exporter les futurs événements d'acquisition.

5. Critères d'admission d'une famille Interface

Une famille n'est admise que si toutes les conditions suivantes sont vraies :

  1. le type est passif et ne possède aucun lifecycle/runtime ;
  2. le fait est provider-neutral ;
  3. il ne duplique pas un modèle persistant/replayable de ksp-store-api ;
  4. l'intersection sémantique entre producers est précise et documentable ;
  5. au moins deux producers/converters peuvent produire exactement ce fait, ou plusieurs consumers ont un besoin identique déjà démontré ;
  6. le type n'est pas une union d'options destinée à masquer des sémantiques différentes ;
  7. les détails non communs peuvent rester sur les DTOs Transport sans forcer Interface à devenir lossless pour le protocole source ;
  8. un usage de composition proche est identifiable.

Une égalité de noms ne suffit pas. Une proximité de commitment ne suffit pas. Une possibilité théorique de conversion ne suffit pas.

6. Inventaire producer -> nature de fait

Producer / surface Nature du fait Champs structurants obligatoires Optionalité utile Ordre / lifecycle Timestamp semantics Error semantics Metadata session/provider Volume potentiel Persistent/replayable ?
Solana WS slotSubscribe progression de slot slot, parent, root aucune event répété à chaque slot traité aucun aucune subscription id hors DTO métier minime non
Solana WS rootSubscribe progression de root root slot aucune event répété lors du changement de root aucun aucune subscription id minime non
Solana WS slotsUpdatesSubscribe lifecycle interne slot slot, type, timestamp parent/stats/error selon variante multi-event par slot ; méthode instable Unix update timestamp en ms texte seulement pour dead subscription id faible à modéré non
Solana WS logsSubscribe logs transaction realtime signature, err, logs + context slot err nullable flux continu selon filtre/commitment aucun provider timestamp opaque RPC transaction error filtre + commitment + subscription id logs non bornés wire non par défaut
Solana WS signatureSubscribe réception/terminal signature signature en request ; context slot + result en event received précoce one-shot terminal ; reçu optionnel avant terminal aucun transaction error au terminal commitment/request/subscription minime non
Solana HTTP getSignatureStatuses snapshot de status signatures request ; slot/status/confirmationStatus nulls/confirmations requête ponctuelle, pas une transition aucun transaction error dans snapshot search history request policy faible queryable côté node, pas event KSP
Solana WS voteSubscribe vote gossip pré-consensus votePubkey, slots, hash, signature timestamp flux gossip ; aucune garantie ledger timestamp vote optionnel aucune erreur transaction canonique subscription id faible non
Solana WS accountSubscribe changement d'état account context slot + account payload selon encoding/dataSlice flux d'état selon commitment aucun payload account, pas error event commitment/encoding/subscription potentiellement élevé peut alimenter RawAccountState
Solana WS programSubscribe changement account d'un programme context + pubkey + account payload selon encoding/filters flux d'état filtré aucun payload account program/filter/commitment/subscription potentiellement élevé peut alimenter RawAccountState
Solana WS blockSubscribe bloc/transactions realtime slot/context + block ou erreur block nullable flux de blocs selon config blockTime dans payload si présent RPC/block error filter/config/subscription très élevé conteneur d'acquisition
Yellowstone Slot lifecycle/commitment slot slot, status parent/dead_error/created_at plusieurs statuts possibles par slot created_at = création serveur update dead diagnostic optionnel filter echo + server metadata faible non
Yellowstone TransactionStatus update execution/status transaction slot, signature, is_vote, index err/created_at flux transaction status server created_at erreur transaction encodée filter echo faible non par lui-même
Yellowstone Account état account + provenance Geyser account bytes/info + slot + is_startup txn signature/created_at flux state/replay startup server created_at decode/transport error hors payload filters + write/version metadata potentiellement élevé peut alimenter RawAccountState
Yellowstone Transaction transaction complète + meta slot + transaction info/meta created_at flux transaction server created_at transaction meta error filters + transaction index très élevé peut alimenter RawTransaction
Yellowstone Block / BlockMeta bloc / metadata de bloc slot + block/meta fields champs block spécifiques flux block/meta server created_at payload/meta-specific filters très élevé conteneur d'acquisition
Yellowstone Entry entry Geyser slot/index/entry-specific fields created_at flux protocol-specific server created_at protocol-specific filters modéré non retenu
Helius standard WebSocket mêmes faits standard Solana mêmes champs standard mêmes optionalités même wire sémantique, runtime provider différent mêmes semantics Solana mêmes semantics Solana Helius session/runtime selon méthode suit la famille standard
Helius Enhanced transactionSubscribe transaction provider-filtered slot/signature ou transaction selon details options/detail modes extension provider continue provider payload semantics provider/RPC semantics filtres Helius + options + session faible à très élevé acquisition possible, Transport-owned
Store notification after commit wake-up de donnée durable future référence durable compacte à définir avec publisher/consumer après commit ; jamais source de vérité non requis par le contrat normatif actuel code safe éventuel, pas payload source mécanisme de diffusion indépendant minime référence une persistence déjà commitée

6.1 Consumers actuels et imminents

Consumer Besoin actuel / prévu Dépendance à Interface event Décision pre.001
ksp-program-api ProgramInstruction / ProgramAccountMeta non préserver la surface Program existante ; aucun re-export acquisition
0.3.6 premier backfill RAW range historique -> Transport -> RAW ingestion -> Store non ne pas forcer SlotLifecycle dans le backfill
futur worker RAW live subscriptions/fetch live multi-transport -> RAW ingestion oui, candidat concret consumer proche justifiant une projection slot lifecycle provider-neutral
futurs processors CORE/DECODE/SPECIALIZED backlog Store + wake-up post-commit non pour event réseau consommer Store/backlog ; ne pas détourner les events réseau
apps de contrôle/inspection futures observabilité et commandes de composants non démontré aucun type Interface ajouté uniquement pour une UI future

7. Matrice de convergence sémantique

Nature candidate Sources comparées Intersection exacte retenue Différences non représentables sans perte Projection commune lossless pour le fait ciblé ? Consumer concret Owner Décision
lifecycle slot slotSubscribe + slotsUpdates + rootSubscribe + Yellowstone Slot Processed, FirstShredReceived, Completed, CreatedBank, Dead, OptimisticallyConfirmed, Rooted Frozen ; parent/timestamps/diagnostics ; noms wire Confirmed/Finalized côté Yellowstone oui, pour l'occurrence slot + stage futur worker RAW live Interface ADMIS
transaction execution logsSubscribe + Yellowstone TransactionStatus + Helius transactionSubscribe slot + TransactionSignature + Succeeded/Failed metadata/provider/detail modes ; commitment/delivery ; erreur source oui pour le fait d'exécution observée futur worker RAW live Interface ADMIS pre.003
logs realtime logsSubscribe + transaction/meta Yellowstone/Helius logs associés à une transaction volume/bornes, richesse de source, disponibilité selon détail non admis dans cette release sans consumer/bornes hydratation possible Interface si futur gate IDÉE DIFFÉRÉE
signature commitment/snapshot getSignatureStatuses + signatureSubscribe identité de signature seulement snapshot HTTP vs transition one-shot commitment non comme event d'exécution aucun contrat unique démontré Transport REPORTÉ
vote voteSubscribe + Yellowstone transaction is_vote qualificatif « vote » seulement gossip pré-consensus vs transaction exécutée non aucun besoin commun démontré Transport REPORTÉ
account/program WS account/program + Yellowstone Account état account complet possible persistance/replay déjà possédés par RawAccountState/Observation non comme event distinct RAW ingestion Store/Transport REJET Interface
transaction complète HTTP/WS/Helius/Yellowstone transaction transaction complète selon source format/commitment/provider metadata ; RawTransaction déjà canonique Store non comme second type RAW ingestion Store/Transport REJET Interface
block getBlock/blockSubscribe/Yellowstone Block slot + block container payloads/options/reconstruction ; pas de consumer passif minimal prouvé non extraction RAW transaction Transport REJET Interface
Yellowstone Entry Yellowstone aujourd'hui aucune multi-source démontrée mono-producer et protocole-specific aujourd'hui non aujourd'hui ; futur fait transversal -> Interface aucun actuel Transport DTO REPORTÉ
persisted-data available Store after commit référence durable compacte conceptuelle event réseau sans relation ; owner déjà normé par KSP-NOTIFY oui mais hors owner Interface processors futurs Store API REJET Interface
Helius Enhanced transaction Helius transactionSubscribe peut produire TransactionExecutionEvent lorsque signature/slot/outcome sont déterminables filtres/options/provider behavior et DTO riche DTO non ; projection sémantique admise via converter futur worker RAW live Transport DTO / Interface fact PRODUCTEUR ADMIS

7.1 Lifecycle de slot — ADMIS sous intersection stricte

Fait commun Solana standard Yellowstone Stage KSP Décision Interface Metadata volontairement non commune
slot traité slotSubscribe Processed Processed ADMIS parent/root courant côté WS ; filters/created_at/parent côté Yellowstone
premier shred reçu FirstShredReceived FirstShredReceived FirstShredReceived ADMIS timestamp WS ; created_at/filters côté Yellowstone
ingestion slot complétée Completed Completed Completed ADMIS timestamp WS ; created_at/filters côté Yellowstone
bank créé CreatedBank CreatedBank CreatedBank ADMIS parent requis WS, optionnel Yellowstone ; il reste dans le DTO Transport riche
slot mort Dead Dead Dead ADMIS diagnostics source-specific et horodatages restent Transport
confirmation optimiste OptimisticConfirmation Confirmed OptimisticallyConfirmed ADMIS le nom KSP conserve la sémantique Solana ; delivery reste Transport
root atteint rootSubscribe / slotsUpdates Root Finalized Rooted ADMIS le nom KSP évite de généraliser Finalized au-delà du mapping audité
frozen Frozen aucun statut exact REJETÉ pas d'intersection

Le fait commun est volontairement plus petit que chaque DTO producteur. La conversion n'efface pas le DTO Transport : elle ajoute une projection passive slot + stage pour les consumers qui n'ont besoin que de l'occurrence de l'étape commune.

Le timestamp n'entre pas dans le contrat commun : slotsUpdatesSubscribe.timestamp décrit l'horodatage Unix de l'update côté validator alors que YellowstoneUpdateTimestamp est une metadata de création serveur. Les réunir sous un seul champ produirait une fausse équivalence.

Le parent, le root courant exposé comme metadata de certaines notifications, dead_error et les détails de delivery restent source-owned ; un consumer qui en a besoin doit conserver le DTO Transport ou définir un contrat supérieur spécifique. Les mappings OptimisticConfirmation -> OptimisticallyConfirmed <- Yellowstone Confirmed et Root -> Rooted <- Yellowstone Finalized sont des normalisations sémantiques documentées, pas des renommages universels des commitments Solana.

7.2 Transaction execution — ADMIS pre.003

pre.003 confirme que l'exécution observée d'une transaction est distincte des snapshots/commitments de signature et possède une intersection multi-producer compacte :

Solana logsSubscribe
    -> context slot + signature base58 + err

Yellowstone TransactionStatus
    -> slot + signature [u8; 64] + err + metadata Yellowstone

Helius transactionSubscribe
    -> slot + signature + résultat d'exécution lorsque le detail mode expose l'erreur

Le contrat admis est :

TransactionSignature([u8; 64])

TransactionExecutionOutcome {
    Succeeded,
    Failed,
}

TransactionExecutionEvent {
    slot,
    signature,
    outcome,
}

Décisions du gate :

  • TransactionSignature est une primitive passive Interface-owned de 64 octets déjà décodés ; Interface n'ajoute ni base58, ni codec, ni dépendance Solana supplémentaire ;
  • cette primitive représente l'identité transactionnelle observée, pas une capability de signature Wallet ;
  • logsSubscribe fournit directement slot, signature et err; err == null produit Succeeded, une erreur produit Failed ;
  • Yellowstone TransactionStatus fournit exactement slot, signature et erreur optionnelle ; is_vote, index, filters et created_at restent Transport ;
  • Helius transactionSubscribe reste provider-specific : une projection n'est produite que lorsque le DTO/detail mode permet de déterminer slot, signature et outcome sans ambiguïté ; une forme none, inconnue ou sans information d'erreur ne fabrique aucun outcome ;
  • commitment, transaction index, logs, memo, block time, confirmation status, provider timestamps et erreurs opaques restent hors Interface ;
  • le futur worker RAW live peut utiliser ce fait comme signal d'acquisition/hydratation provider-neutral sans le confondre avec une donnée RAW persistée.

TransactionSignature ne remplace pas ksp-store-api::RawTransactionSignature. Les deux contrats ont des owners distincts : Interface possède l'identité compacte d'un event-only fact, Store possède l'identité d'une référence RAW persistante. La conversion explicite entre les deux appartient à la composition conformément à DEP-KSP-003; aucune dépendance Interface -> Store n'est introduite.

Les DTOs logsSubscribe, Yellowstone TransactionStatus et Helius transactionSubscribe restent intégralement Transport-owned. Interface ne contient aucun converter depuis ces types.

7.3 Logs realtime et signature commitment — DIFFÉRENCIÉS

Les logs ne sont plus utilisés comme argument pour rejeter l'exécution commune : logsSubscribe peut produire un TransactionExecutionEvent sans que les lignes de logs entrent dans le contrat partagé.

Une éventuelle famille distincte reste une idée différée :

TransactionLogEvent {
    slot,
    signature,
    logs,
}

Elle n'est pas admise en 0.3.5 tant que les bornes, la disponibilité multi-producer et un consumer concret ne sont pas démontrés. Aucun RawLog n'est créé.

Les surfaces de commitment/snapshot restent séparées de l'exécution :

HTTP getSignatureStatuses
    = snapshot interrogé, avec confirmations/status/confirmationStatus

WS signatureSubscribe
    = transition one-shot vers le commitment demandé, éventuellement précédée de ReceivedSignature

Aucun TransactionCommitmentEvent n'est admis. Une future famille de commitment devra être auditée indépendamment et ne pourra pas être fusionnée avec TransactionExecutionEvent par une struct à nombreux Option.

7.4 Vote — REPORTÉ

voteSubscribe est explicitement pré-consensus et ne garantit pas l'entrée du vote dans le ledger. Le booléen is_vote de la famille transaction Yellowstone qualifie une transaction et n'est pas une notification gossip équivalente.

Aucun VoteEvent partagé n'est admis.

7.5 Account/program — REJET Interface

Les updates account/program peuvent contenir l'état complet nécessaire à l'acquisition RAW. ksp-store-api possède déjà :

RawAccountState
RawAccountObservation

Créer un second account event structurel dans Interface serait soit :

  • un doublon persistant déguisé ;
  • un wrapper des DTOs Transport ;
  • un type incomplet qui perd les conditions d'admission RAW.

La conversion Transport -> Store API reste à la composition.

7.6 Transaction/block — REJET Interface

RawTransaction et RawTransactionObservation sont déjà Store-owned. Les blocs servent de conteneurs d'acquisition ou de payloads Transport riches. Aucun RawBlock, TransactionEvent ou BlockEvent transversal n'est ajouté.

7.7 Yellowstone Entry — Transport aujourd'hui, ownership sémantique réservé

SubscribeUpdateEntry reste un DTO Yellowstone strictement Transport-owned : un seul producer/protocole est démontré aujourd'hui et aucun consumer transversal proche ne justifie un type partagé. Cette décision ne réserve toutefois pas le fait à Transport : si une future seconde source permet de reconstruire un même LedgerEntryEvent provider-neutral, ce nouveau fait passif devra être audité pour ownership Interface, sans déplacer le DTO Yellowstone lui-même.

7.8 Notification after commit — REJET Interface

Les règles KSP-NOTIFY-001..006 sont explicites : le format canonique du signal « persisted data available » appartient à ksp-store-api, est publié après commit et ne constitue jamais le backlog. 0.3.5 ne crée aucun équivalent Interface.

8. API sketch admise

La seule API planifiée pour pre.002 est conceptuellement :

#[non_exhaustive]
pub enum SlotLifecycleStage {
    Processed,
    FirstShredReceived,
    Completed,
    CreatedBank,
    Dead,
    OptimisticallyConfirmed,
    Rooted,
}

pub struct SlotLifecycleEvent {
    slot: u64,
    stage: SlotLifecycleStage,
}

Surface publique visée :

SlotLifecycleStage
SlotLifecycleEvent::new(slot, stage)
SlotLifecycleEvent::slot()
SlotLifecycleEvent::stage()

Décisions de représentation :

SlotLifecycleStage  -> #[non_exhaustive] + Clone + Copy + Debug + Eq + PartialEq
SlotLifecycleEvent  -> champs privés + Clone + Copy + Debug + Eq + PartialEq
Hash                 -> absent tant qu'un consumer réel ne l'exige pas
validation           -> aucune borne variable ; slot u64 conservé exactement
error code           -> aucun ; aucune admission faillible n'est nécessaire

Contraintes :

  • pas de serde imposé ;
  • pas de String, JSON, bytes, timestamp ou diagnostic ;
  • pas de network id dupliquant RawNetworkId ; la composition est déjà liée à son contexte réseau ;
  • Debug est sûr par construction ;
  • aucun error code n'est nécessaire si tout u64 de slot et toute variante publique construite sont valides ;
  • aucune dépendance nouvelle n'est requise ;
  • aucun trait universel Event, EventSource, Subscriber ou Handler ;
  • aucune conversion From<TransportType> dans Interface, car cela créerait une dépendance interdite ;
  • les converters appartiennent au futur consumer/composition ou, si un usage concret le justifie plus tard, à une crate de composition dédiée.

Le nom final peut être ajusté pendant pre.002 seulement si les canaris montrent une ambiguïté réelle. Le sens slot + stage commun ne doit pas être élargi. OptimisticallyConfirmed et Rooted sont volontairement préférés à Confirmed et Finalized afin de conserver la sémantique KSP du fait normalisé sans transformer les labels Yellowstone en terminologie universelle.

9. Consumer proche et usage concret

L'architecture prévoit un futur worker RAW live :

subscriptions/fetch live
    -> ksp-onchain-transport-lib
    -> RAW ingestion
    -> D1 RAW

Ce worker est le consumer proche qui peut recevoir des événements de progression/lifecycle de slot venant soit des WebSockets standard, soit de Yellowstone sans connaître les DTOs des deux protocoles lorsqu'il n'a besoin que de déclencher/ordonner une réaction de composition propre au lifecycle.

Le même worker peut consommer TransactionExecutionEvent comme signal compact qu'une signature a été exécutée dans un slot avec succès ou échec, puis décider dans sa propre policy/composition s'il doit hydrater/persister un RawTransaction. Le fait Interface ne contient ni payload ni provenance et n'est jamais utilisé comme preuve durable de présence dans Store.

Ces APIs ne deviennent pas un prérequis de 0.3.6 : le premier backfill historique reste fondé sur Transport + Store et peut ne jamais consommer les events Interface.

10. Anti-duplication Store

Contrat Store comparé Chevauchement Interface admis Pourquoi il n'y a pas de seconde vérité
RawTransaction slot + signature possibles via execution event aucun payload/format/hash/block_time ; l'event ne peut reconstruire ni remplacer une transaction RAW
RawTransactionReference signature sémantiquement apparentée la référence Store inclut RawNetworkId et possède l'identité durable ; Interface reste contextuel
RawTransactionSignature même primitive protocolaire 64 octets wrapper Store et primitive Interface restent owner-specific ; conversion explicite à la composition
RawTransactionObservation référence transaction possible indirectement aucune provenance acquisition, observation key ou timestamp durable
RawAccountState slot possible via lifecycle seulement aucune pubkey/state hash/lamports/owner/data ; aucun état account
RawAccountObservation slot indirect possible aucune référence account/provenance Geyser
RawAcquisitionProvenance aucun pas d'origin/provider code/timestamps ; les metadata source restent Transport/composition
RawTimestamp aucun aucun timestamp commun inventé
RawContentHash aucun aucune identité de contenu durable
RawObservationKey aucun aucune identité d'observation persistante
notification after commit aucun event réseau observe l'acquisition ; wake-up Store référence une donnée déjà commitée

Le gate conserve les canaris conceptuels suivants :

SlotLifecycleEvent -X-> RawTransaction
TransactionExecutionEvent -X-> RawTransaction
TransactionExecutionEvent -X-> RawTransactionObservation
TransactionSignature -X-> RawTransactionSignature implicit conversion
Interface -X-> ksp-store-api
Interface -X-> ksp-store-lib
Store API -X-> Interface

Une couche de composition peut convertir explicitement TransactionSignature::as_bytes() vers RawTransactionSignature::new(...), mais aucun From cross-domain n'est possédé par Interface ou Store API. Aucun champ d'un event admis ne constitue à lui seul une preuve RAW durable.

11. Graphe cible

Après implémentation de la release :

ksp-interface-lib
└── ksp-core-lib

Aucune nouvelle dependency normale ou feature n'est planifiée.

Les consumers restent :

ksp-program-api
    -> ksp-interface-lib  # ProgramInstruction / ProgramAccountMeta seulement

future acquisition composition / RAW live worker
    -> ksp-onchain-transport-lib
    -> ksp-interface-lib  # SlotLifecycleEvent / TransactionExecutionEvent
    -> ksp-store-lib / ksp-store-api selon ownership

12. Threat model

Risque Menace Garde planifiée
mega enum Interface devient catalogue de tous les transports familles admises séparées et étroites ; aucun Event générique
Option soup sémantiques différentes fusionnées par champs optionnels familles séparées : SlotLifecycle / TransactionExecution ; logs/commitment restent distincts
persistence creep event-only devient second Store aucun RAW/payload/cursor/retention ; KSP-NOTIFY-* reste Store API
transport wrapper copie des DTOs WS/gRPC/provider aucune metadata protocol/provider dans le type Interface
faux timestamp commun horodatages WS et Yellowstone confondus aucun timestamp partagé
root/finality confusion label Yellowstone Finalized promu comme vérité universelle stage KSP Rooted ; mapping source explicite Root <-> Yellowstone Finalized sans renommer le fait KSP
optimistic/confirmed confusion label Yellowstone Confirmed promu comme commitment générique stage KSP OptimisticallyConfirmed ; mapping source explicite avec l'optimistic confirmation Solana
dead diagnostic leak texte provider/validator traverse une API partagée durable stage Dead sans diagnostic ; détail reste Transport
cross-network confusion event sans réseau mélangé entre sessions conversion autorisée seulement dans une composition déjà liée à un contexte réseau ; pas de network id dupliqué
signature/payload leak signature ou payload brut fuit via Debug signature fixe 64 octets, Debug redacted ; aucun payload variable
public enum breakage ajout futur casse les matches externes SlotLifecycleStage et TransactionExecutionOutcome non-exhaustive
logging/runtime creep crate passive acquiert tracing/Tokio/channel aucune dependency/runtime/logging ajoutée
Helius semantic promotion DTO/provider extension devient norme KSP transactionSubscribe reste Transport ; seule une projection sémantique commune peut devenir Interface
Yellowstone protocol promotion DTO Entry/filters/created_at deviennent Interface types Yellowstone restent Transport ; un futur fait transversal est réaudité séparément

13. Stratégie de tests

13.1 pre.002 — modèle admis

Tests unitaires Interface :

  • chaque stage public est distinct ;
  • slot est conservé sans narrowing ;
  • le constructeur/getters sont passifs et déterministes ;
  • le type n'emporte aucune metadata de transport.

Tests d'intégration :

  • crate-root public API ;
  • external consumer ;
  • dependency boundary Core-only ;
  • exact production module/export inventory.

13.2 pre.003 — transaction execution admis

Tests unitaires Interface :

  • TransactionSignature conserve exactement 64 octets et masque ses bytes en Debug ;
  • Succeeded et Failed sont distincts ;
  • TransactionExecutionEvent conserve u64::MAX, signature et outcome sans narrowing ;
  • Debug d'event ne rend pas la signature.

Tests d'intégration :

  • les trois nouveaux symboles sont disponibles depuis le crate-root ;
  • TransactionExecutionOutcome impose un wildcard downstream via #[non_exhaustive] ;
  • l'inventaire crate-root passe de 8 à 11 reexports ;
  • l'inventaire de production ajoute uniquement transaction_execution.

13.3 Convergence sans dépendance Transport

ksp-interface-lib ne doit pas ajouter ksp-onchain-transport-lib même en dépendance normale pour « tester » les converters. Les preuves d'équivalence sémantique restent dans le plan/validation de release et les canaris de frontière Interface.

Si un converter concret est introduit plus tard dans une crate de composition, sa propre crate devra tester les mappings exacts :

SolanaSlotNotification -> Processed
SolanaSlotUpdate::FirstShredReceived -> FirstShredReceived
SolanaSlotUpdate::Completed -> Completed
SolanaSlotUpdate::CreatedBank -> CreatedBank
SolanaSlotUpdate::Dead -> Dead
SolanaSlotUpdate::OptimisticConfirmation -> OptimisticallyConfirmed
SolanaRoot / SolanaSlotUpdate::Root -> Rooted
YellowstoneSlotStatus::Confirmed -> OptimisticallyConfirmed
YellowstoneSlotStatus::Finalized -> Rooted
YellowstoneSlotStatus autres équivalents -> mêmes stages

Et devra explicitement refuser Frozen ou toute variante future sans mapping audité au lieu d'inventer un faux stage commun.

13.4 Traçabilité des candidats différés

TransactionExecutionEvent est admis par pre.003 et n'est donc plus un TODO. TransactionLogEvent reste explicitement une idée différée. Si cette idée reste hors scope à la réconciliation documentaire finale, elle doit être reportée dans la surface TODO/IDEAS durable appropriée au lieu d'être perdue avec le plan de release.

14. Prévision souple des prereleases

La release reste dimensionnée pour une seule session. SlotLifecycleEvent est matérialisé en pre.002 et TransactionExecutionEvent devient la seconde famille admise en pre.003; aucune troisième famille n'est ouverte sans nouveau gate.

0.3.5-pre.001 — audit + plan

  • lecture des règles/architectures/surfaces ;
  • audit externe actuel ;
  • matrice producer/fact et convergence ;
  • ownership et anti-duplication Store ;
  • threat model ;
  • API sketch ;
  • sizing et plan de release.

0.3.5-pre.002SlotLifecycleEvent

  • implémenter la famille minimale admise ;
  • crate-root exports ;
  • tests unitaires et public API ciblés ;
  • préserver le graphe Core-only.

0.3.5-pre.003TransactionExecutionEvent

  • gate signature/dependency : PASS avec TransactionSignature([u8; 64]) passive, sans codec ni dépendance supplémentaire ;
  • mappings Solana logsSubscribe / Yellowstone TransactionStatus / Helius transactionSubscribe : PASS sous projection conservative ;
  • anti-duplication Store : PASS, conversion explicite Interface <-> Store à la composition ;
  • consumer concret : PASS, futur worker RAW live ;
  • implémenter TransactionSignature, TransactionExecutionOutcome et TransactionExecutionEvent seulement ;
  • ne pas introduire logs, commitment, metadata provider ou converters Transport dans Interface.

0.3.5-pre.004 — canaris externes + complétude API

  • external consumer pour toutes les familles effectivement admises ;
  • inventaire exact des modules/exports ;
  • canaris négatifs contre Transport/Store/runtime/serde/logging ;
  • non-exhaustive et stabilité de la surface.

0.3.5-pre.005 — hardening final

  • adversarial/API hardening ;
  • absence de payload/source metadata ;
  • absence de second RAW ;
  • validation du graphe et des dépendances ;
  • aucun élargissement fonctionnel opportuniste.

0.3.5-pre.006 — gate technique final

  • gates Rust/workspace complets ;
  • cargo tree Interface normal/features/duplicates ;
  • aucun smoke live requis : les contrats Interface restent passifs et ne possèdent aucun réseau.

0.3.5-pre.007 — réconciliation documentaire finale

  • plan + validation réconciliés avec le gate pre.006 propre ;
  • README/USAGE Interface durables et version-neutral ;
  • rôle Interface explicité dans les documents d'architecture réellement devenus incomplets ;
  • TransactionLogEvent transféré dans docs/IDEAS.md comme idée différée ;
  • aucun CHANGELOG/ROADMAP/prompt suivant dans cette tranche.

0.3.5-pre.008 — préparation de publication

Lane minimale :

Cargo.toml
CHANGELOG.md
ROADMAP.md
prompts/025-V0_3_6_START_PROMPT.md
deltas/0.3.5/pre.008.md

Aucun code, README/USAGE, plan ou validation ne doit être rouvert ici.

0.3.5-rel.001 — stable

  • mécanique de publication uniquement ;
  • version Cargo finale 0.3.5 ;
  • aucun rattrapage fonctionnel/documentaire.

15. Gates opérateur

15.1 Après chaque overlay fonctionnel

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.3.5
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-interface-lib

Ajouter cargo test -p ksp-program-api lorsqu'une modification publique Interface pourrait affecter son consumer actuel.

15.2 Gate technique final

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.3.5
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-interface-lib
cargo test --workspace
cargo tree -p ksp-interface-lib --edges normal
cargo tree -p ksp-interface-lib -e features
cargo tree --duplicates

Aucun live test n'est justifié par 0.3.5 : un type passif ne doit pas acquérir de dépendance réseau pour prouver son existence.

16. Hors périmètre

grand enum Event
event bus / channel / broadcaster
scheduler / worker / job
backfill 0.3.6
persistence ou migration Store
nouvelle capability Store
RawLog / RawBlock
TransactionStatusObservation fusionné
TransactionCommitmentEvent fusionné avec execution
TransactionLogEvent sans nouveau gate de bornes/consumer
VoteEvent partagé
label KSP `Finalized` utilisé comme alias universel de root
label KSP `Confirmed` utilisé comme alias universel d'optimistic confirmation
Helius Enhanced DTO dans Interface
Yellowstone Entry DTO dans Interface
serde/wincode/borsh ajouté sans protocole réel
logging/runtime dans Interface
conversion Transport -> Interface possédée par Interface

17. Critère de clôture de 0.3.5

La release peut fermer si et seulement si :

une famille minimale SlotLifecycle est publique et bornée
intersection = Processed + FirstShredReceived + Completed + CreatedBank + Dead + OptimisticallyConfirmed + Rooted
Frozen et toute variante future sans mapping audité ne sont pas normalisées artificiellement
TransactionExecutionEvent est admis en pre.003 sous la forme minimale slot + TransactionSignature + outcome
aucun payload/diagnostic/timestamp/provider metadata n'entre dans Interface
Interface reste Core-only
Store RAW 10/10 reste inchangé
KSP-NOTIFY ownership reste Store API
aucun event bus/runtime/persistence n'est ajouté
external consumer et crate-root canaries passent
README/USAGE finaux restent durables et version-neutral

Si l'implémentation montre qu'un de ces invariants ne peut pas être préservé, la famille SlotLifecycle est retirée plutôt qu'élargie artificiellement.