v0.0.3-pre.006

This commit is contained in:
2026-08-14 12:07:18 +02:00
parent 63bb90a46d
commit 2cb9f809b7
14 changed files with 1126 additions and 67 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/IDEAS.md -->
<!-- version: 9 -->
<!-- version: 10 -->
# Idées à explorer
@@ -209,3 +209,39 @@ Ne pas imposer cette composition dans `ksp-execution-policy-api` avant qu'un cas
**Status :** À explorer avec la première UI concernée
Définir un mécanisme sûr de suspension/reprise d'une exécution lorsque la policy demande une approbation externe, sans faire dépendre la couche execution d'une UI ou de Tauri.
## Data / Store — questions d'implémentation
### Schémas SQL D1/D2/D3/D4
**Status :** À explorer avec la première release Store
La structure durable D1D4 est retenue, mais les noms de tables, colonnes, contraintes, index et repositories doivent être conçus avec les premiers workloads réels.
### Format générique D3
**Status :** À explorer
Le journal D3 doit accepter les outputs de materializers officiels ou externes sans nécessiter une nouvelle table par materializer.
À définir : identité/type/domain, payload, hash, provenance, version processor, état current/superseded/failed/replay et stratégie de sérialisation.
### Backlog et checkpoints
**Status :** À explorer en `pre.007`
Les notifications restent des wake-ups. Définir comment chaque worker/job interroge le Store pour retrouver les inputs non traités par une version donnée, avec pagination, batching, reprise et concurrence.
### Jobs de replay
**Status :** À explorer en `pre.007`
Prévoir des jobs séparés pour D1 -> D2, D2 -> D3 et D3 -> D4 plutôt qu'un replay monolithique obligatoire.
Les noms définitifs ne sont pas encore retenus.
### Notification backend de référence
**Status :** À explorer en `pre.007`
PostgreSQL LISTEN/NOTIFY est un candidat naturel pour la première implémentation de signal de réveil, mais le contrat doit rester indépendant du mécanisme et le Store reste la source de vérité.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/000-README.md -->
<!-- version: 6 -->
<!-- version: 7 -->
# Architecture KSP
@@ -23,6 +23,7 @@ Ils ne remplacent ni `ROADMAP.md`, ni les plans de version, ni les deltas.
4. [`004-COMPONENT_INVENTORY.md`](004-COMPONENT_INVENTORY.md) — inventaire courant des domaines, APIs, bibliothèques, workers, jobs, scénarios et applications candidates ;
5. [`005-DEPENDENCY_GRAPH.md`](005-DEPENDENCY_GRAPH.md) — graphe de dépendances retenu, dépendances interdites et frontières de conversion/composition ;
6. [`006-WIRE_AND_PROGRAM.md`](006-WIRE_AND_PROGRAM.md) — propriété des contrats wire, politique de dépendances codecs/interfaces, API Program ouverte, preparation d'exécution et extensibilité externe ;
7. [`007-EXECUTION_AND_POLICY.md`](007-EXECUTION_AND_POLICY.md) — policy multi-checkpoints, orchestration transactionnelle, wallet/transport, retry, approval externe et résultat d'exécution.
7. [`007-EXECUTION_AND_POLICY.md`](007-EXECUTION_AND_POLICY.md) — policy multi-checkpoints, orchestration transactionnelle, wallet/transport, retry, approval externe et résultat d'exécution ;
8. [`008-DATA_MATERIALIZATION_AND_STORE.md`](008-DATA_MATERIALIZATION_AND_STORE.md) — niveaux durables D1D4, Materialization, Store PostgreSQL de référence, provenance, idempotence, replay et notifications de données persistées.
`004-COMPONENT_INVENTORY.md` et `005-DEPENDENCY_GRAPH.md` sont maintenus ensemble : une évolution du graphe qui change le propriétaire d'une responsabilité doit corriger l'inventaire au lieu de laisser deux descriptions contradictoires.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/002-LAYERS_AND_DEPENDENCIES.md -->
<!-- version: 3 -->
<!-- version: 4 -->
# Couches et dépendances KSP
@@ -7,6 +7,8 @@
Les niveaux N1 à N4 servent à raisonner sur les responsabilités, la stabilité et le sens des dépendances. Ils ne constituent pas une chaîne d'appels obligatoire.
Les niveaux durables de données utilisent une nomenclature distincte **D1 à D4** afin de ne jamais être confondus avec les couches architecturales N1 à N4 : D1 Raw, D2 Core canonique, D3 journal de matérialisation générique et D4 projections spécialisées.
Une couche supérieure peut dépendre directement d'une bibliothèque KSP plus basse lorsque cette bibliothèque est exactement la propriétaire de la capacité recherchée.
## N1 — Fondations
@@ -74,7 +76,7 @@ Les consommateurs des notifications W1 décident eux-mêmes s'ils doivent décod
### Workers de processing futurs
Le processing continu n'est plus modélisé comme un unique W2. La direction actuelle sépare `ksp-worker-core-processor`, `ksp-worker-generic-materializer` et `ksp-worker-domain-projector` afin de respecter les frontières durables raw -> Core -> matérialisation générique -> projections de domaine. Leur détail sera repris dans la tranche consacrée aux workers/data.
Le processing continu n'est plus modélisé comme un unique W2. La direction actuelle sépare `ksp-worker-core-processor`, `ksp-worker-generic-materializer` et `ksp-worker-domain-projector` afin de respecter les frontières durables D1 Raw -> D2 Core -> D3 journal de matérialisation générique -> D4 projections de domaine. Leur détail sera repris dans la tranche consacrée aux workers/data.
## N4 — Exécutables

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/003-COMPONENT_CONTRACTS.md -->
<!-- version: 7 -->
<!-- version: 8 -->
# Contrats initiaux des composants KSP
@@ -9,7 +9,7 @@ Ce document enregistre les frontières déjà suffisamment claires pour guider l
Le principe commun est de définir tôt les contrats nécessaires entre composants, puis d'enrichir les implémentations lorsque le besoin réel apparaît.
L'inventaire détaillé courant est maintenu dans [`004-COMPONENT_INVENTORY.md`](004-COMPONENT_INVENTORY.md), le graphe autorisé/interdit dans [`005-DEPENDENCY_GRAPH.md`](005-DEPENDENCY_GRAPH.md), Wire/Program dans [`006-WIRE_AND_PROGRAM.md`](006-WIRE_AND_PROGRAM.md) et Execution/Policy dans [`007-EXECUTION_AND_POLICY.md`](007-EXECUTION_AND_POLICY.md).
L'inventaire détaillé courant est maintenu dans [`004-COMPONENT_INVENTORY.md`](004-COMPONENT_INVENTORY.md), le graphe autorisé/interdit dans [`005-DEPENDENCY_GRAPH.md`](005-DEPENDENCY_GRAPH.md), Wire/Program dans [`006-WIRE_AND_PROGRAM.md`](006-WIRE_AND_PROGRAM.md) Execution/Policy dans [`007-EXECUTION_AND_POLICY.md`](007-EXECUTION_AND_POLICY.md) et Data/Materialization/Store dans [`008-DATA_MATERIALIZATION_AND_STORE.md`](008-DATA_MATERIALIZATION_AND_STORE.md).
## Convention API / implémentation
@@ -88,13 +88,15 @@ Une application Tauri peut exceptionnellement avoir une dépendance/framework tr
## Frontière materializer / store
`ksp-materializer-api` peut dépendre de `ksp-program-api` pour consommer des contrats de processing communs.
Les niveaux durables utilisent D1 Raw, D2 Core canonique, D3 journal de matérialisation générique et D4 projections spécialisées.
`ksp-materializer-api` peut dépendre de `ksp-program-api` pour consommer des contrats Core ouverts. Il doit pouvoir distinguer conceptuellement une matérialisation générique D2 -> D3 et une projection spécialisée D3 -> D4.
`ksp-materializer-lib` reste une bibliothèque de transformation et ne dépend ni de `ksp-store-api` ni de `ksp-store-lib`.
`ksp-store-api` possède les DTO/contrats persistants et reste indépendant des APIs Program/Materializer. Les workers de processing convertissent explicitement entre modèles runtime et modèles persistants.
`ksp-store-api` possède les DTO/contrats persistants et reste indépendant des APIs Program/Materializer. Les workers/jobs de processing convertissent explicitement entre modèles runtime et modèles persistants.
Cette règle évite d'introduire un `ksp-data-api` monolithique uniquement pour partager des modèles entre couches.
D3 est un journal durable obligatoire ; D4 reste plus évolutif. Cette séparation évite d'introduire un `ksp-data-api` monolithique uniquement pour partager des modèles entre couches.
## Transport on-chain
@@ -122,7 +124,9 @@ Aucune `ksp-wallet-api` n'est prévue.
`ksp-store-api` reste la frontière backend-agnostic. `ksp-store-lib` contient PostgreSQL comme implémentation de référence.
Les notifications de données persistées sont normalisées indépendamment de leur producteur. W1, un job de backfill ou un import utilisent le même contrat pour signaler le même type de donnée.
Les notifications de données persistées sont normalisées indépendamment de leur producteur. W1, un job de backfill, un import ou un replay utilisent le même contrat pour signaler le même type de donnée.
Une notification est seulement un signal de réveil : le Store et les marqueurs d'idempotence/backlog restent la source de vérité. La publication suit l'ordre `persist -> commit -> notify`.
Le contrat de notification est distinct de son transport concret.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/004-COMPONENT_INVENTORY.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# Inventaire initial des composants KSP
@@ -9,7 +9,7 @@ Ce document constitue le premier inventaire architectural de `0.0.3-pre.002`.
Il répond principalement à la question : **quel composant possède quelle responsabilité ?**
Le premier inventaire a été produit en `0.0.3-pre.002`. `pre.003` l'a corrigé à partir du graphe, puis `pre.004` a détaillé Wire/Program dans [`006-WIRE_AND_PROGRAM.md`](006-WIRE_AND_PROGRAM.md). Les détails de types Rust restent révisables avec les premières implémentations.
Le premier inventaire a été produit en `0.0.3-pre.002`. `pre.003` l'a corrigé à partir du graphe, puis `pre.004` a détaillé Wire/Program dans [`006-WIRE_AND_PROGRAM.md`](006-WIRE_AND_PROGRAM.md), `pre.005` Execution/Policy et `pre.006` les niveaux durables/Materialization/Store dans [`008-DATA_MATERIALIZATION_AND_STORE.md`](008-DATA_MATERIALIZATION_AND_STORE.md). Les détails de types Rust restent révisables avec les premières implémentations.
## Statuts
@@ -38,7 +38,7 @@ Le premier inventaire a été produit en `0.0.3-pre.002`. `pre.003` l'a corrigé
| Materializer API | `ksp-materializer-api` | API | N3 contrat | Retenu | `0.3.x` | contrats publics/extensibles de matérialisation |
| Materializer impl. | `ksp-materializer-lib` | lib | N3 | Retenu | `0.3.x+` | materializers officiels KSP |
| Store API | `ksp-store-api` | API | N3 contrat | Retenu | `0.3.x` | contrats backend-agnostic, modèles persistants et notifications de données persistées |
| Store impl. | `ksp-store-lib` | lib | N3 | Retenu | `0.3.x` | PostgreSQL de référence, migrations, repositories, queries |
| Store impl. | `ksp-store-lib` | lib | N3 | Retenu | `0.3.x` | PostgreSQL de référence, migrations, repositories, queries, backlog/replay et notification backend |
| Worker lifecycle | `ksp-worker-api` | API | N3 contrat | Retenu | `0.3.x` | lifecycle commun des services continus |
| Worker control | `ksp-worker-control-lib` | lib | N3 | Retenu | `0.3.x+` | gouvernance réutilisable des workers pour managers/apps/orchestrateur |
| Live raw acquisition | `ksp-worker-raw-retriever` | worker | N4 | Retenu | `0.3.x` | acquisition live/quasi-live -> raw persisté -> notification data |

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/005-DEPENDENCY_GRAPH.md -->
<!-- version: 3 -->
<!-- version: 4 -->
# Graphe de dépendances KSP
@@ -349,11 +349,23 @@ ksp-materializer-lib
-> ksp-core-lib
```
`ksp-interface-lib` peut être consommée par `ksp-materializer-lib` lorsqu'une matérialisation a réellement besoin d'un contrat wire déjà possédé par KSP, mais ne doit pas devenir une dépendance obligatoire de toute matérialisation.
`ksp-interface-lib` peut être consommée par une implémentation de materializer lorsqu'un contrat wire officiel est réellement requis, sans devenir une dépendance obligatoire de l'API.
## Décision importante
## Capacités
Ni `ksp-materializer-api` ni `ksp-materializer-lib` ne dépendent du store.
`ksp-materializer-api` doit permettre de distinguer conceptuellement :
```text
GenericMaterializer
D2 runtime/Core -> output générique D3
DomainProjector
D3/canonical inputs -> output spécialisé D4
```
Les noms exacts ne sont pas figés.
## Indépendance du Store
```text
ksp-materializer-api -X-> ksp-store-api
@@ -361,9 +373,9 @@ ksp-materializer-lib -X-> ksp-store-api
ksp-materializer-lib -X-> ksp-store-lib
```
Une matérialisation transforme des données ; le worker/job/pipeline spécialisé persiste le résultat.
Un materializer transforme ; un worker/job/pipeline spécialisé convertit son output vers le DTO Store et le persiste.
Cette séparation permet également de tester un materializer externe sans PostgreSQL.
Une implémentation externe peut produire un output générique D3 sans migration PostgreSQL spécialisée.
---
@@ -376,13 +388,24 @@ ksp-store-api
ksp-store-lib
-> ksp-store-api
-> ksp-core-lib
-> ksp-config-lib
-> ksp-logging-lib
```
`ksp-store-lib` peut dépendre de config/logging et contient PostgreSQL comme implémentation de référence.
PostgreSQL est l'implémentation de référence.
## Indépendance du store
## Niveaux durables
Le store ne dépend pas des implémentations Program/Materializer/Transport :
```text
D1 Raw
D2 Core canonique
D3 journal de matérialisation générique
D4 projections spécialisées
```
`ksp-store-api` possède les contrats persistants de ces niveaux sans dépendre des modèles runtime de Program/Materializer/Transport.
Interdictions :
```text
ksp-store-api -X-> ksp-program-api
@@ -394,33 +417,46 @@ ksp-store-lib -X-> ksp-materializer-lib
ksp-store-lib -X-> ksp-onchain-transport-lib
```
`ksp-store-api` définit les DTO/contrats persistants nécessaires aux niveaux durables sans imposer les modèles runtime des processors.
Les composants de composition réalisent les conversions explicites.
## Notifications de données persistées
## Replay
`ksp-store-api` est retenu comme propriétaire du contrat canonique de notification lorsqu'il signifie :
Les frontières de replay restent indépendantes :
> une donnée persistée de telle catégorie est disponible.
```text
D1 -> D2
D2 -> D3
D3 -> D4
```
Le même contrat est utilisé quelle que soit l'origine :
Les jobs de replay consomment le Store et les processors appropriés ; ils ne sont pas des modes des workers live.
## Notifications persistées
`ksp-store-api` possède le contrat canonique de notification lorsqu'une donnée durable est disponible.
```text
live worker ----\
backfill job ----+--> persisted data notification
backfill job ----+--> PersistedDataAvailable (nom conceptuel)
import ----------/
replay ----------/
```
Le mécanisme de diffusion reste hors du contrat :
La notification est un signal de réveil et peut être perdue ou dupliquée.
Le consumer reconstruit toujours son backlog via le Store, les versions de processor et les marqueurs d'idempotence.
L'ordre est :
```text
channel
LISTEN/NOTIFY
IPC
broker
...
persist
commit
notify
```
Le mode de transport concret sera détaillé en `pre.005`.
Le payload privilégie une référence durable compacte.
Le mécanisme concret peut être channel, PostgreSQL LISTEN/NOTIFY, IPC ou broker. Le choix détaillé est reporté à `pre.007`.
---
@@ -474,7 +510,7 @@ Un futur orchestrateur peut utiliser workers et jobs séparément sans créer de
Les dépendances ci-dessous décrivent la composition attendue. Les détails de processus/IPC seront approfondis plus tard.
## `ksp-worker-raw-retriever`
## `ksp-worker-raw-retriever` — transport -> D1
```text
ksp-worker-raw-retriever
@@ -509,9 +545,9 @@ ksp-job-backfill
-> ksp-logging-lib
```
Il utilise la même famille de DTO raw persistants et la même notification de données persistées que W1.
Il produit exactement la même famille de DTO D1 persistants et la même notification de données persistées que le worker live.
## `ksp-worker-core-processor`
## `ksp-worker-core-processor` — D1 -> D2
```text
ksp-worker-core-processor
@@ -541,7 +577,7 @@ store Core DTO
`ksp-program-lib` ne connaît donc pas le store.
## `ksp-worker-generic-materializer`
## `ksp-worker-generic-materializer` — D2 -> D3
```text
ksp-worker-generic-materializer
@@ -554,9 +590,9 @@ ksp-worker-generic-materializer
-> ksp-logging-lib
```
La frontière exacte des entrées/sorties génériques sera détaillée en `pre.005`.
Il consomme le backlog D2, appelle la capacité de matérialisation générique puis persiste le journal D3. La notification éventuelle accélère le traitement mais ne remplace pas la query de backlog.
## `ksp-worker-domain-projector`
## `ksp-worker-domain-projector` — D3 -> D4
```text
ksp-worker-domain-projector
@@ -571,7 +607,7 @@ ksp-worker-domain-projector
Son nom reste provisoire.
Il est propriétaire de la composition entre résultats de matérialisation spécialisée et projections persistantes par domaine ; `ksp-materializer-lib` reste indépendant du backend.
Il est propriétaire de la composition entre D3, la projection/materialisation spécialisée et les DTO D4 persistants ; `ksp-materializer-lib` reste indépendant du backend. D4 est organisé par faits canoniques plutôt que par familles de tables propres aux protocoles.
---

View File

@@ -0,0 +1,732 @@
<!-- file: docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md -->
<!-- version: 1 -->
# Data, Materialization et Store
## Objet
Ce document constitue la sortie principale de `0.0.3-pre.006`.
Il définit les frontières durables de données KSP et précise :
- les niveaux D1 à D4 ;
- la séparation `ksp-materializer-api` / `ksp-materializer-lib` / Store ;
- le rôle backend-agnostic de `ksp-store-api` ;
- PostgreSQL comme implémentation de référence de `ksp-store-lib` ;
- provenance et temporalités ;
- idempotence et versionnement des processors ;
- replay indépendant par frontière ;
- sémantique des notifications de données persistées ;
- stabilité différente entre niveaux structurants et projections spécialisées.
Cette tranche ne détaille pas encore le lifecycle complet, batching, concurrence ou supervision des workers/jobs. Ces sujets sont déplacés vers `pre.007`.
## Nomenclature des niveaux durables
Les niveaux de données ne réutilisent pas N1 à N4, déjà réservés aux couches architecturales KSP.
La nomenclature durable retenue est :
```text
D1 — Raw
D2 — Core canonique
D3 — Journal de matérialisation générique
D4 — Projections spécialisées/queryables par domaine
```
Flux général :
```text
source on-chain
|
v
ksp-worker-raw-retriever
|
v
D1 Raw
|
v
ksp-worker-core-processor
|
v
D2 Core canonique
|
v
ksp-worker-generic-materializer
|
v
D3 journal générique
|
v
ksp-worker-domain-projector
|
v
D4 projections de domaine
```
Le nom `ksp-worker-domain-projector` reste révisable ; la frontière D3 -> D4 est, elle, retenue.
# D1 — Raw
## Mission
D1 conserve l'acquisition suffisamment fidèlement pour permettre un nouveau processing sans redemander la donnée à la blockchain lorsque l'information nécessaire a déjà été capturée.
`raw` ne signifie pas nécessairement « enveloppe propriétaire du provider conservée sans aucune normalisation ». Le transport peut normaliser ses différentes sources vers des modèles KSP homogènes.
La persistance D1 doit toutefois rester **lossless pour les besoins de replay couverts** : toute information nécessaire à la reconstruction du Core doit être conservée, y compris le contenu brut et la provenance utile.
## Frontière transport -> D1
```text
Solana RPC ------\
Helius -----------+--> modèle homogène ksp-onchain-transport-lib
Yellowstone ------/
|
v
conversion explicite
|
v
DTO D1 de ksp-store-api
```
`ksp-onchain-transport-lib` ne dépend ni de `ksp-store-api` ni de `ksp-store-lib`.
La conversion appartient au composant de composition, principalement `ksp-worker-raw-retriever` ou `ksp-job-backfill`.
## Provenance D1
Selon la catégorie de donnée, D1 doit pouvoir conserver notamment :
- réseau ;
- identité blockchain : slot, signature, pubkey ou autre identifiant applicable ;
- contenu raw/replayable ;
- provider ;
- transport/source ;
- rôle d'acquisition : live, backfill, import ou autre ;
- instant d'observation/acquisition ;
- instant de persistence ;
- hash/identité d'idempotence ;
- informations de pagination/capture nécessaires à la reprise lorsque pertinentes.
`block_time` reste optionnel et n'est jamais inventé lorsqu'il n'est pas fourni ou reconstructible de manière fiable.
# D2 — Core canonique
## Mission
D2 contient les faits canoniques Solana produits à partir de D1.
Le Core doit être suffisamment durable et général pour être rejoué vers les matérialisations futures sans repasser par l'acquisition ou le décodage raw.
Conceptuellement, D2 peut accueillir notamment :
- transactions canoniques ;
- instructions top-level ;
- instructions CPI ;
- comptes/états canoniques ;
- résultats de décodage Program ouverts ;
- événements/return data lorsqu'ils sont supportés ;
- autres faits génériques Solana qui appartiennent réellement au Core.
## Top-level / CPI
Les instructions top-level et CPI restent des faits distincts.
Leur modèle peut partager des champs, mais KSP ne doit pas les fusionner artificiellement lorsque leurs invariants ou requêtes diffèrent.
La séparation physique exacte sera décidée dans la première release Store.
## Frontière D1 -> D2
```text
DTO D1 store
|
v
ksp-worker-core-processor
|
+--> conversion vers entrée ksp-program-api
|
+--> ksp-program-lib / extension compatible
|
+--> sortie Core ouverte
|
v
conversion vers DTO D2 store
```
`ksp-program-api` / `ksp-program-lib` restent indépendants du Store.
## Provenance D2
D2 doit pouvoir relier un résultat à :
- son input D1 ;
- l'identité/version du processor ;
- l'identité/version de l'implémentation Program/decoder lorsque pertinente ;
- la capacité de décodage utilisée ;
- un hash de l'input logique ;
- l'instant de processing/persistence ;
- l'état de processing lorsqu'un lifecycle durable est nécessaire.
# D3 — Journal de matérialisation générique
## Mission
D3 est un **journal durable**, pas une étape volatile.
Il conserve l'équivalent conceptuel obligatoire de l'ancien journal `k_sol_mat_outputs` de `ks-store`, sans figer encore le nom exact de la table KSP.
Il doit permettre de répondre à des questions telles que :
```text
quel input D2 ?
quel materializer ?
quelle version ?
quel output logique ?
quel type/domaine ?
quel hash ?
quel instant ?
quel état courant/superseded/failed/replay ?
```
D3 permet notamment de reconstruire D4 après évolution d'un projector sans refaire D1 -> D2 ou D2 -> D3.
## Frontière D2 -> D3
```text
D2 Core
|
v
ksp-worker-generic-materializer
|
+--> conversion vers ksp-materializer-api
|
+--> GenericMaterializer
|
v
generic materialization output
|
v
conversion vers DTO D3 store
```
Les noms Rust exacts ne sont pas figés.
## Extensibilité externe
Une implémentation externe de materializer doit pouvoir produire un output générique compatible avec D3 sans exiger une nouvelle table PostgreSQL spécialisée.
Cela rend possible :
```text
external materializer
|
v
ksp-materializer-api
|
v
D3 journal générique
```
avant une éventuelle intégration officielle complète en D4.
# D4 — Projections spécialisées de domaine
## Mission
D4 contient les représentations optimisées pour les requêtes métier, analytiques et produit.
Exemples futurs :
- assets/tokens ;
- metadata d'assets/tokens ;
- Solana Program Metadata ;
- liquidity pools ;
- order books ;
- swaps/trades ;
- prices/volumes ;
- positions ;
- autres projections de domaine.
## Faits canoniques, pas familles par protocole
D4 reste organisé par **fait canonique**, pas par Program ID/protocole.
Éviter par défaut :
```text
meteora_pools
raydium_pools
orca_pools
```
au profit d'une projection canonique telle que :
```text
liquidity_pools
```
avec provenance/identité du protocole lorsque nécessaire.
La même règle s'applique aux swaps, order books et autres faits pouvant être normalisés.
## Metadata
Les metadata d'assets/tokens constituent une famille canonique commune pouvant recevoir des données provenant notamment :
- Metaplex Token Metadata ;
- Token-2022 Metadata.
Solana Program Metadata reste une projection distincte car le domaine fonctionnel est différent.
## Nouvelle projection externe
Une nouvelle projection D4 relationnelle implique nécessairement un contrat de persistence et une implémentation backend.
KSP ne masque pas cette réalité derrière une API de matérialisation « magique ».
Une extension externe peut fonctionner jusqu'à D3 sans migration Store spécialisée. Pour obtenir une nouvelle projection D4 officielle, il faut intégrer :
- le contrat DTO/repository approprié dans `ksp-store-api` ;
- la migration/repository PostgreSQL dans `ksp-store-lib` ;
- la conversion/projector appropriée dans le composant de processing.
Un mécanisme de backend/projection entièrement externe pourra être étudié seulement si un besoin concret apparaît.
# Stabilité des niveaux durables
La direction retenue est :
```text
D1 — fortement stable
D2 — fortement stable
D3 — fortement stable
D4 — volontairement plus évolutif
```
Après stabilisation de la première série Store réelle, les contrats D1/D2/D3 doivent changer seulement en cas :
- d'erreur structurelle ;
- d'omission majeure ;
- de nécessité de compatibilité impossible à résoudre additivement.
D4 peut évoluer plus librement lorsque de nouveaux décodeurs, materializers ou produits révèlent des besoins queryables supplémentaires.
# `ksp-materializer-api`
## Rôle
Une seule crate publique est retenue :
```text
ksp-materializer-api
```
Elle expose les contrats de matérialisation réutilisables sans dépendre du Store.
Deux capacités conceptuelles doivent pouvoir être distinguées :
```text
GenericMaterializer
DomainProjector
```
Les noms exacts restent à valider.
### GenericMaterializer
Transforme une représentation Core/runtime en output générique persistable en D3.
### DomainProjector
Transforme un ou plusieurs inputs génériques/canoniques en représentation spécialisée de domaine destinée à D4.
Le second contrat peut évoluer en fonction des premiers cas réels. La séparation des responsabilités est plus importante que le nom du trait.
## Dépendances
```text
ksp-materializer-api
-> ksp-core-lib
-> ksp-program-api
```
Pas de dépendance vers Store.
# `ksp-materializer-lib`
`ksp-materializer-lib` contient les implémentations officielles KSP de `ksp-materializer-api`.
Organisation conceptuelle possible :
```text
generic/
...
domain/
metadata/
token/
dex/
...
```
La structure finale suivra les règles de domaine établies avec les premières implémentations.
Interdictions :
```text
ksp-materializer-lib -X-> ksp-store-api
ksp-materializer-lib -X-> ksp-store-lib
```
Un materializer transforme ; il ne persiste pas directement.
Le worker/job/pipeline spécialisé relie la transformation à la persistence.
# `ksp-store-api`
## Rôle
`ksp-store-api` expose la frontière backend-agnostic de persistence KSP.
Il possède les contrats persistants correspondant aux niveaux durables :
```text
raw
core
materialization
domain
```
La structure exacte des modules Rust sera définie avec la première implémentation.
`ksp-store-api` ne dépend pas de Program, Materializer ou Transport.
## Contrats génériques et contrats de domaine
D1/D2/D3 doivent rester génériques et fortement structurants.
D4 peut croître progressivement avec les domaines officiellement supportés.
Cette différence est volontaire : l'API Store doit pouvoir ajouter de nouvelles projections queryables sans déstabiliser les contrats de replay historiques.
# `ksp-store-lib`
`ksp-store-lib` est l'implémentation officielle de référence de `ksp-store-api`.
PostgreSQL est le backend de référence prévu.
La crate possède notamment :
- configuration backend/connexion ;
- pool/transactions backend ;
- migrations ;
- repositories ;
- queries ;
- persistence D1/D2/D3/D4 ;
- primitives de backlog/replay nécessaires au backend ;
- mécanismes PostgreSQL de notification lorsqu'ils sont retenus.
Les autres crates KSP ne contournent pas `ksp-store-lib` pour exécuter directement leurs propres opérations PostgreSQL.
Un second backend n'est pas créé abstraitement ; il devra justifier l'évolution de l'architecture lorsqu'un besoin réel apparaît.
# Temporalités
Les temporalités blockchain et locales sont distinctes.
Exemples blockchain :
```text
slot
block_time: Option<...>
```
Exemples locaux :
```text
observed_at
acquired_at
persisted_at
processed_at
materialized_at
projected_at
```
Toutes ne doivent pas nécessairement être présentes dans chaque DTO/table. Leur sémantique doit cependant être explicite lorsqu'elles existent.
Aucune date locale ne remplace silencieusement un `block_time` absent.
# Provenance
Un niveau dérivé doit permettre de remonter à son input durable et au processor qui l'a produit.
## D1
Provenance d'acquisition :
- network ;
- provider/source ;
- transport ;
- rôle d'acquisition ;
- identité blockchain ;
- temporalités d'observation/persistence.
## D2
En plus :
- input D1 ;
- processor/decoder identity ;
- processor/decoder version ;
- input hash ;
- processing time/state.
## D3
En plus :
- input D2 ;
- materializer identity/version ;
- output identity/type/domain ;
- output/input hash ;
- materialization time/state.
## D4
En plus :
- input(s) D3 ou références canoniques explicitement définies ;
- projector identity/version ;
- projection time/state.
La représentation exacte de la provenance sera conçue pour éviter de répéter inutilement de gros payloads.
# Idempotence et versionnement
Chaque frontière dérivée doit pouvoir rejouer le même input sans créer de doublons logiquement distincts.
Principe conceptuel :
```text
same logical input
+ same processor identity
+ same processor version
+ same logical output identity
= same durable result
```
Une nouvelle version du processor doit pouvoir coexister avec ou superséder le résultat précédent selon la politique du niveau.
Le système doit pouvoir représenter selon besoin des états tels que :
```text
current
superseded
pending
failed
replay
```
Les noms, colonnes et contraintes SQL exacts seront décidés avec la première implémentation.
L'idempotence ne doit pas reposer uniquement sur l'espoir qu'une notification soit livrée une seule fois.
# Replay
Les replays sont séparés par frontière durable :
```text
D1 -> D2
D2 -> D3
D3 -> D4
```
Ils doivent pouvoir être exécutés indépendamment.
Exemples :
- nouveau decoder/Core processor : rejouer D1 -> D2 ;
- nouveau materializer générique : rejouer D2 -> D3 ;
- nouvelle version d'un projector : rejouer D3 -> D4.
Il ne doit pas être nécessaire de refaire toute la chaîne lorsqu'un niveau inférieur inchangé contient déjà l'information requise.
Les replays sont des **jobs bornés**, pas des modes cachés des workers live.
Les noms exacts des futurs jobs de replay sont reportés à `pre.007`.
# Notifications de données persistées
## Contrat
`ksp-store-api` est le propriétaire du contrat canonique lorsqu'une notification signifie :
> une donnée durable de telle catégorie/référence est disponible.
Le même type de donnée utilise le même format de notification quelle que soit son origine :
```text
worker live
backfill job
import
replay
autre source
```
## Notification != source de vérité
Une notification est un **signal de réveil/accélération**, jamais la source de vérité du backlog.
Elle peut être :
- perdue ;
- dupliquée ;
- retardée ;
- reçue après un restart.
Le consumer doit toujours pouvoir reconstruire son travail depuis le Store.
Exemple conceptuel :
```text
notification RawAvailable
|
v
wake-up core worker
|
v
store query:
"quels inputs D1 ne sont pas encore traités
par CoreProcessor version X ?"
```
Le Store, l'idempotence et les checkpoints durables constituent la vérité.
Cette règle évite d'exiger immédiatement un broker exactly-once.
## Ordre de publication
Une donnée n'est annoncée disponible qu'après persistence réussie :
```text
persist
commit
notify
```
et non :
```text
notify
persist
```
## Payload
La notification privilégie une référence durable compacte plutôt que la duplication de tout le payload :
- catégorie/type ;
- réseau ;
- identifiant/range/cursor durable ;
- autres informations minimales nécessaires au consumer.
Les noms de DTO exacts restent à définir.
## Mécanisme de diffusion
Le contrat est indépendant du mécanisme.
Candidats :
```text
channel in-process
PostgreSQL LISTEN/NOTIFY
IPC
broker externe
```
`ksp-store-lib` peut fournir PostgreSQL LISTEN/NOTIFY comme mécanisme de référence si cela répond au premier besoin.
Le choix détaillé des mécanismes, reprise, batching et multi-process est reporté à `pre.007`.
# Acquisition live et backfill
`ksp-worker-raw-retriever` et `ksp-job-backfill` diffèrent par leur lifecycle/orchestration mais produisent le **même contrat D1** pour la même catégorie de donnée.
```text
live source ----------\
+--> D1 Raw
historical backfill --/
```
Cela garantit que le processing downstream ne dépend pas de la manière dont la donnée a été acquise.
Le backfill n'est pas un mode historique du worker live.
# Workers de processing
Les frontières de responsabilité sont désormais :
```text
ksp-worker-raw-retriever
transport -> D1
ksp-worker-core-processor
D1 -> D2
ksp-worker-generic-materializer
D2 -> D3
ksp-worker-domain-projector
D3 -> D4
```
Chaque worker :
- peut utiliser les notifications pour réduire la latence ;
- doit pouvoir reconstruire son backlog depuis le Store ;
- écrit seulement le niveau durable dont il est propriétaire ;
- ne transforme pas silencieusement plusieurs frontières en une étape monolithique.
Le détail lifecycle, concurrence, batching, cursors, checkpoints et hot reconfiguration est reporté à `pre.007`.
# Projections de trading et autres domaines
Le trading reste une priorité produit mais ne détermine pas la structure D1/D2/D3.
D4 doit accueillir progressivement des faits canoniques de nombreux domaines :
- token ;
- metadata ;
- staking ;
- programmes ;
- trading/DEX ;
- autres domaines futurs.
Pour le trading, les materializers/projectors doivent normaliser les noms et structures propres aux protocoles vers des faits communs lorsque les invariants le permettent.
# Questions laissées ouvertes
La première implémentation Store devra encore fixer :
- schémas SQL et noms exacts des tables ;
- clés/idempotence exactes ;
- représentation des hashes ;
- états de processing exacts ;
- temporalités obligatoires/optionnelles par table ;
- format exact des DTO D1/D2/D3 ;
- structure des repositories/transactions backend ;
- pagination/cursors ;
- conversion u64/slot/PostgreSQL ;
- stratégie des migrations initiales.
`pre.007` doit préciser :
- lifecycle des quatre workers ;
- jobs de replay ;
- checkpoint/backlog ;
- batching/concurrence ;
- mécanisme de notification de référence ;
- processus/IPC selon les managers retenus.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/001-V0_0_3_PLAN.md -->
<!-- version: 9 -->
<!-- version: 10 -->
# Plan KSP 0.0.3
@@ -13,7 +13,7 @@ Transformer le brainstorming KSP en architecture, règles, inventaire et plan su
- `pre.002` — inventaire initial des composants ;
- `pre.003` — graphe de dépendances, correction de l'inventaire et stabilisation des frontières de composition.
Les tranches `pre.004` (Wire/Program) et `pre.005` (Execution/Policy) sont maintenant cadrées/livrées séparément afin de conserver des prereleases de planification bornées.
Les tranches `pre.004` (Wire/Program), `pre.005` (Execution/Policy) et `pre.006` (Data/Materialization/Store) sont maintenant livrées séparément afin de conserver des prereleases de planification bornées.
## Décisions structurantes actuelles
@@ -82,17 +82,36 @@ Livré :
- résultat d'exécution indépendant du Store ;
- `ksp-logging-lib` confirmé comme façade unique tracing du runtime KSP, avec dépendance possible vers Core pour `Error`/`Result`.
### `pre.006` — Données, store et acquisitions
### `pre.006` — Data, Materialization et Store
- détailler `ksp-materializer-api` / `ksp-materializer-lib` ;
- détailler `ksp-store-api` / `ksp-store-lib` ;
- finaliser modèles raw/Core/generic/domain ;
- détailler notifications et mécanismes de diffusion possibles ;
- détailler W1 et backfill ;
- cadrer les workers de processing ;
- revisiter niveaux durables, replay, provenance et idempotence.
Livré :
### `pre.007` — Applications, workers, jobs, scenarios et pipelines spécialisés
- nomenclature durable D1 Raw / D2 Core / D3 journal générique / D4 projections spécialisées ;
- D1/D2/D3 fortement stabilisables et D4 plus évolutif ;
- D3 confirmé comme journal durable obligatoire ;
- frontière `ksp-materializer-api` / `ksp-materializer-lib` sans dépendance Store ;
- capacités conceptuelles de matérialisation générique et projection de domaine ;
- `ksp-store-api` backend-agnostic et `ksp-store-lib` PostgreSQL de référence ;
- provenance et temporalités par niveau ;
- idempotence/versionnement processors ;
- replays indépendants D1 -> D2, D2 -> D3, D3 -> D4 ;
- notifications après commit comme wake-up uniquement, Store comme source de vérité ;
- même contrat D1 pour acquisition live et backfill ;
- D4 par faits canoniques plutôt que tables par protocole.
### `pre.007` — Acquisition, workers de processing et jobs
- détailler `ksp-worker-raw-retriever` ;
- détailler `ksp-worker-core-processor` ;
- détailler `ksp-worker-generic-materializer` ;
- détailler `ksp-worker-domain-projector` et réévaluer son nom ;
- détailler `ksp-job-backfill` ;
- définir les jobs de replay D1 -> D2, D2 -> D3, D3 -> D4 ;
- définir backlog/checkpoints/cursors ;
- traiter batching, concurrence, reprise et hot reconfiguration ;
- choisir le mécanisme de notification de référence sans en faire la source de vérité.
### `pre.008` — Applications, managers, scenarios et orchestration
- formaliser les apps spécialisées ;
- détailler `ksp-worker-control-lib` ;
@@ -101,14 +120,14 @@ Livré :
- cadrer l'orchestrateur futur ;
- inventorier les pipelines spécialisés réellement nécessaires.
### `pre.008` — Plan des premières releases fonctionnelles
### `pre.009` — Plan des premières releases fonctionnelles
- transformer les séries `0.1.x+` en premières releases concrètes ;
- dimensionner chaque release concrète ;
- choisir la première release `0.1.N` ;
- transformer le brouillon de prompt en prompt quasi-final de cette release concrète.
### `pre.009` — Clôture fondatrice
### `pre.010` — Clôture fondatrice
- validations finales de cohérence ;
- documentation/nettoyage/archivage ;

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_DEPENDENCIES.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# Règles des dépendances KSP
@@ -61,9 +61,15 @@ Elles complètent les règles Rust générales et le graphe de `docs/architectur
- **DEP-MAT-001** — `ksp-materializer-api` peut dépendre de `ksp-program-api` lorsque les contrats de matérialisation consomment des sorties canoniques de processing.
- **DEP-MAT-002** — `ksp-materializer-api` et `ksp-materializer-lib` ne dépendent pas de `ksp-store-api` ou `ksp-store-lib`.
- **DEP-MAT-003** — Une matérialisation générique doit pouvoir produire un output compatible avec le journal D3 sans imposer une table PostgreSQL spécialisée par materializer.
- **DEP-STORE-001** — `ksp-store-api` ne dépend pas de Program, Materializer ou Transport.
- **DEP-STORE-002** — `ksp-store-lib` dépend de `ksp-store-api` et contient l'implémentation PostgreSQL de référence ; il ne dépend pas des implémentations Program/Materializer/Transport.
- **DEP-STORE-003** — Les workers/jobs spécialisés sont propriétaires des conversions entre modèles runtime et DTO persistants.
- **DEP-STORE-004** — Les niveaux durables sont D1 Raw, D2 Core canonique, D3 journal de matérialisation générique et D4 projections spécialisées.
- **DEP-STORE-005** — Les replays D1 -> D2, D2 -> D3 et D3 -> D4 doivent pouvoir être exécutés indépendamment.
- **DEP-STORE-006** — Une notification de donnée persistée ne constitue jamais la source de vérité du backlog ; les queries Store et marqueurs durables d'idempotence/version de processor font autorité.
- **DEP-STORE-007** — Une notification de donnée est publiée seulement après persistence/commit réussis.
- **DEP-STORE-008** — D4 est organisé par faits canoniques quand les invariants le permettent, et non par familles de tables propres aux protocoles.
## Transport

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_KSP.md -->
<!-- version: 9 -->
<!-- version: 10 -->
# Règles spécifiques à KSP
@@ -65,6 +65,33 @@
- **KSP-WIRE-002** — Les interfaces externes sont sélectionnées aussi selon la modernité/cohérence de leur graphe de dépendances, pas uniquement selon la commodité de leur API.
- **KSP-WIRE-003** — Les contrats wire d'une crate protocolaire rejetée sont réimplémentés de manière bornée dans `ksp-interface-lib` lorsque KSP en a besoin.
## Niveaux durables et Store
- **KSP-DURABLE-001** — Les niveaux persistants utilisent la nomenclature D1 à D4, distincte des couches architecturales N1 à N4.
- **KSP-DURABLE-002** — D1 est Raw, D2 Core canonique, D3 le journal générique de matérialisation et D4 les projections spécialisées/queryables.
- **KSP-DURABLE-003** — D1/D2/D3 sont destinés à devenir fortement stables après stabilisation de la première série Store ; D4 reste plus évolutif.
- **KSP-DURABLE-004** — Le journal D3 est durable et obligatoire ; il ne peut pas être supprimé au profit de projections D4 directes.
- **KSP-DURABLE-005** — Les replays D1 -> D2, D2 -> D3 et D3 -> D4 sont indépendants.
- **KSP-DURABLE-006** — Les instructions top-level et CPI restent des faits Core distincts lorsque leurs invariants/requêtes diffèrent.
- **KSP-DURABLE-007** — D4 modélise des faits canoniques plutôt que des familles de tables par protocole lorsque les invariants sont normalisables.
- **KSP-DURABLE-008** — Les temporalités blockchain et locales restent distinctes ; un `block_time` absent n'est jamais remplacé par une date locale inventée.
## Materialization
- **KSP-MAT-001** — `ksp-materializer-api` est l'unique API publique de matérialisation actuellement prévue et peut exposer des capacités distinctes D2 -> D3 et D3 -> D4.
- **KSP-MAT-002** — `ksp-materializer-lib` transforme mais ne persiste pas directement et ne dépend pas du Store.
- **KSP-MAT-003** — Une extension externe de materializer doit pouvoir produire du D3 générique sans migration PostgreSQL spécialisée.
- **KSP-MAT-004** — Une nouvelle projection relationnelle D4 exige explicitement un contrat Store/migration/backend correspondant ; cette responsabilité n'est pas cachée dans `ksp-materializer-api`.
## Notifications de données persistées
- **KSP-NOTIFY-001** — `ksp-store-api` possède le format canonique d'une notification signalant qu'une donnée persistée est disponible.
- **KSP-NOTIFY-002** — Le format est indépendant de l'origine de la donnée : worker live, backfill, import, replay ou autre source.
- **KSP-NOTIFY-003** — Une notification est un signal de réveil et n'est jamais la source de vérité du backlog.
- **KSP-NOTIFY-004** — La persistence et le commit réussissent avant publication d'une notification.
- **KSP-NOTIFY-005** — Le payload de notification privilégie une référence durable compacte plutôt que la duplication du payload persistant.
- **KSP-NOTIFY-006** — Le contrat de notification reste indépendant du mécanisme de diffusion concret.
## Workers
- **KSP-WORKER-001** — Un worker représente un service continu/live ; il est distinct d'un job.