# Data, Materialization et Store ## Objet Ce document définit la chaîne durable KSP, la responsabilité du Store et les frontières de replay. La nomenclature canonique est désormais : ```text RAW -> CORE -> DECODE -> SPECIALIZED ``` Les aliases D1–D4 restent utilisés pour les niveaux persistés : ```text D1 = RAW D2 = CORE D3 = DECODE / matérialisation générique décodée D4 = SPECIALIZED ``` Cette clarification remplace l'ancienne interprétation où D1 -> D2 pouvait déjà dépendre de `ksp-program-api`. **RAW et CORE sont indépendants de tout decoder Program.** ## Principes structurants - le Store persiste des contrats de données ; il ne possède ni transport, ni decoder, ni materializer ; - chaque frontière durable peut être rejouée indépendamment ; - les données de provenance/versioning permettent de savoir quel processor a produit quel output ; - les couches dérivées ne rendent jamais obligatoire une nouvelle acquisition réseau lorsque l'input durable nécessaire existe déjà ; - D4 privilégie les faits métier génériques lorsqu'une normalisation inter-protocoles est pertinente. ## D1 — RAW ### Mission RAW conserve l'acquisition suffisamment fidèlement pour reconstruire CORE sans redemander la donnée au provider lorsqu'elle a déjà été capturée. Le transport peut normaliser plusieurs providers vers un modèle KSP homogène, mais D1 doit rester lossless pour les besoins de replay couverts. D1 ne décode aucun programme Solana/SPL/Metaplex/DEX. ### Frontière Transport -> RAW ```text HTTP / WS / gRPC / provider | v ksp-onchain-transport-lib | v conversion explicite | v ksp-store-api RAW DTO | v ksp-store-lib ``` `ksp-onchain-transport-lib` ne dépend ni de `ksp-store-api` ni de `ksp-store-lib`. ### Provenance RAW Selon la catégorie, D1 doit pouvoir conserver notamment : - cluster/network ; - slot/signature/pubkey/identité blockchain applicable ; - payload replayable ; - provider ; - endpoint/source/transport ; - rôle d'acquisition : live, backfill, import ; - instant d'observation ; - instant de persistence ; - identité/hash d'idempotence ; - cursor/page/range/checkpoint lorsque pertinent. ## D2 — CORE ### Mission CORE est une **normalisation canonique générique de la blockchain Solana**. Cette couche doit fonctionner même si `ksp-program-api` et `ksp-program-lib` ne sont pas encore capables de décoder le moindre programme métier. Exemples de faits CORE candidats : - slots ; - blocks et block metadata ; - signatures ; - transactions ; - messages legacy/versioned ; - account keys et address lookups ; - comptes et états bruts structurés génériquement ; - instructions top-level brutes ; - instructions CPI brutes ; - logs ; - transaction meta ; - balances/fees/rewards lorsqu'ils appartiennent au contrat blockchain générique ; - return data brute ; - relations structurelles transaction/message/instruction/account. Un fait CORE peut contenir un `program_id`, des bytes et des indexes sans savoir que l'instruction représente un `Transfer`, un `Swap` ou une mutation Metadata. ### Frontière RAW -> CORE ```text D1 RAW | v normalisation Solana générique | v D2 CORE ``` Interdictions : ```text RAW -> CORE -X-> ksp-program-api RAW -> CORE -X-> ksp-program-lib RAW -> CORE -X-> ksp-materializer-api ``` Les codecs/wires génériques nécessaires à la structure Solana peuvent provenir de `ksp-interface-lib` lorsqu'ils appartiennent à la façade wire officielle, sans transformer cette étape en décodage Program. ### Provenance CORE D2 doit pouvoir relier chaque résultat à : - son input D1 ; - l'identité/version du normalizer CORE ; - un hash logique d'input ; - l'instant de processing/persistence ; - son état de processing durable lorsque nécessaire. ## D3 — DECODE / matérialisation générique ### Mission DECODE commence lorsque KSP interprète un `program_id`, un layout d'instruction, un compte ou un événement selon un contrat Program/protocole. La progression logique d'un groupe est : ```text CORE | v decoder Program | v decoded facts | v materialisation générique / journal durable | v D3 DECODE ``` D3 conserve l'équivalent conceptuel obligatoire du journal générique de matérialisation de bot3 (`k_sol_mat_outputs`), sans imposer son ancien schéma ou son nom physique. Le journal doit pouvoir répondre au minimum : ```text quel input CORE ? quel program/decoder ? quelle version ? quel materializer ? quelle version ? quel output logique ? quel type/domaine ? quel hash ? quel instant ? quel état/superseded/failed/replay ? ``` Les types exacts de decoded facts et du journal sont décidés lorsque les premiers vertical slices Program existent. ### Frontière CORE -> DECODE ```text D2 CORE | v ksp-program-api implementation | v decoded output | v ksp-materializer-api implementation | v D3 journal / decoded materialization ``` Les implémentations officielles pourront provenir de `ksp-program-lib` et `ksp-materializer-lib`; des implémentations externes compatibles restent possibles. Program et Materializer ne dépendent pas du backend Store. ## D4 — SPECIALIZED ### Mission SPECIALIZED expose des projections queryables utiles aux applications, analyses et futurs modèles ML. Exemples : - token/asset state ; - metadata canonique d'asset ; - pools/markets ; - reserves/liquidity ; - positions ; - swaps/trades ; - fees ; - observations de prix ; - OHLC/candles ; - routes et legs ; - faits trading-adjacent ; - projections d'autres domaines futurs. ### Faits métier génériques Les projections de trading ne sont pas séparées automatiquement par protocole. Préférer lorsque possible : ```text liquidity_pools trades positions price_observations ohlc routes route_legs ``` plutôt que : ```text meteora_trades raydium_trades orca_trades pump_trades ``` Les champs réellement protocol-specific peuvent être conservés dans une extension ou une projection dédiée uniquement lorsqu'un besoin de requête/invariant le justifie. ### Metadata La direction reste : - projection canonique commune pour metadata d'assets/tokens alimentée par Metaplex Token Metadata et Token-2022 Metadata ; - SPM reste distinct et sera redéveloppé plus tard avec le décodage généraliste. ### OHLC Les candles sont des projections SPECIALIZED calculées à partir des trades/price observations persistés. Une application marché lit les OHLC matérialisés ; elle ne reparcourt pas toutes les transactions pour reconstruire les candles à chaque affichage. ## Vertical slices Program RAW et CORE sont développés horizontalement. À partir de DECODE, la progression est verticale par groupe : ```text wire -> decode -> generic materialization / D3 -> specialized projection / D4 si utile -> execution preparation -> execution policy -> execution -> Devnet scenarios / validation ``` Un groupe doit atteindre une cohérence verticale suffisante avant que le groupe suivant devienne prioritaire. Les composants satellites nécessaires à un protocole appartiennent à son groupe : Pump fees avec Pump, Meteora vaults avec Meteora, etc. ## `ksp-store-api` `ksp-store-api` est backend-agnostic et porte les contrats nécessaires aux consommateurs. La première implementation `0.3.1` est volontairement **RAW-only** : elle ne crée pas prématurément les contrats physiques D2/D3/D4. Les surfaces CORE/DECODE/SPECIALIZED sont ajoutées quand leurs couches sont réellement ouvertes. ## `ksp-store-lib` et backends physiques `ksp-store-lib` est la façade/runtime Store commune derrière `ksp-store-api`. Il sélectionne uniquement les backends compilés par ses features, convertit ses settings KSP-owned vers le backend retenu, expose le lifecycle commun et masque les objets physiques du moteur. Il possède notamment : - identité et sélection de backend côté façade ; - settings Store publics KSP-owned indépendants de Config ; - lifecycle commun `open` / `close` ; - dispatch vers le backend compilé ; - mapping des diagnostics/health backend vers une projection portable lorsque cette surface est justifiée ; - réexport de la surface `ksp-store-api` utile aux consumers. Le backend PostgreSQL officiel appartient à `ksp-store-postgres-lib`. Cette crate dépend de `ksp-store-api`, ne dépend jamais de `ksp-store-lib` et possède seule : - `tokio-postgres` et le pool PostgreSQL ; - le connecteur TLS PostgreSQL ; - SQL et statements physiques ; - transactions PostgreSQL ; - migrations/bootstrap et metadata de schéma ; - mapping rows/backend ; - détails de cursorisation physique ; - diagnostics PostgreSQL internes. `ksp-store-lib` et les crates backend ne possèdent pas : - transport réseau d’acquisition ; - decoder Program ; - materializer ; - orchestration de worker/job ; - politique de batch, backlog, priorité ou retry de processing. La pagination/cursorisation reste un contrat de navigation Store. Une limite demandée par l’appelant peut être validée pour sa forme/sécurité, mais aucun plafond métier global arbitraire ni batch-size de worker n’est introduit par le runtime Store. ### Navigation machine et inspection humaine Deux contrats complémentaires coexistent sans collision : ```text workers / jobs / replay -> RawPageRequest + RawPageCursor -> keyset inspection UI -> RawInspectionPageRequest -> offset + limit + counts exacts ``` La voie cursor/keyset reste canonique pour la navigation machine et les replays : le cursor est opaque, lié au contexte de query et ne dépend pas d'un `OFFSET` profond. La voie `RawInspectionPageRequest` est backend-neutral mais conçue pour une inspection humaine random-access. Elle peut demander des counts exacts et un offset absolu ; le backend PostgreSQL peut implémenter cette capability avec `COUNT` et `OFFSET` privés. Ce choix ne réécrit jamais les statements keyset historiques. `ksp-app-store-desk` est le consumer actuel de cette voie d'inspection. DataTables possède l'unique pager visible et l'application ne reçoit aucun cursor Store. Les summaries d'inspection restent sans payload/data RAW ; un détail explicite peut recharger une seule entité avec une projection applicative bornée. ## `ksp-materializer-api` et `ksp-materializer-lib` Ils sont introduits seulement lorsque le premier groupe DECODE démontre le contrat réel. `ksp-materializer-api` porte les contrats extensibles ; `ksp-materializer-lib` contient les implementations officielles communes. Une projection très locale/spécifique peut rester dans son groupe si la création d'une implémentation commune séparée n'apporte pas de réutilisation réelle. ## Replay Les frontières durables restent replayables indépendamment : ```text RAW -> CORE CORE -> DECODE DECODE -> SPECIALIZED ``` Un replay d'une couche dérivée ne doit pas refaire arbitrairement les couches précédentes. ## Notifications persistées Le Store reste source de vérité du backlog. Les notifications ne sont qu'un wake-up : elles peuvent être perdues ou dupliquées. Ordre : ```text persist commit notify ``` Le consumer reconstruit toujours son backlog depuis le Store avec les versions de processor et les marqueurs d'idempotence. ## Acquisition live et backfill Live et backfill alimentent la même frontière RAW : ```text live worker ----\ +--> RAW persistence backfill job ----/ ``` Ils ne dupliquent pas le contrat durable. ## Stabilité La stabilité cible est différente selon la couche : - RAW : fortement stable après mise en production ; - CORE : fortement stable après validation de la normalisation Solana générique ; - DECODE : extensible par nouveaux Program/versions ; - SPECIALIZED : plus évolutif selon les besoins de query, trading et analytics. ## Questions laissées ouvertes - schémas SQL exacts RAW puis CORE ; - représentation persistable exacte d'un decoded output ; - contrat exact du journal D3 ; - granularité des projectors SPECIALIZED ; - politique de supersession/versioning des outputs ; - fenêtres OHLC initiales ; - mécanisme de contexte pour les projections stateful.