44 KiB
Plan 0.3.1 — Store API RAW foundation
1. Statut et base
Ce plan est établi par 0.3.1-pre.001 à partir de la release stable v0.2.14 et de l'archive historique obligatoire khadhroony-bot3_v0.5.3-pre.005-fix010.zip.
La base KSP vérifiée à l'ouverture est :
workspace.package.version = 0.2.14
deltas/0.2.14/rel.001.md présent
prompts/020-V0_3_1_START_PROMPT.md présent
ksp-program-api présent
ksp-store-api absent
ksp-store-lib absent
L'archive opérateur ne contient pas de metadata Git exploitable ; le tag v0.2.14 ne peut donc pas être revérifié localement. La version Cargo, le delta rel.001, le prompt 020 et la surface Program API publiée concordent avec la base stable attendue.
Le journal opérateur fourni avec l'archive montre un baseline stable intégralement vert avant ouverture de 0.3.1 : audits Rust/Markdown, cargo check --workspace, Clippy et cargo test --workspace passent.
Après application de pre.001, la version Cargo cible est :
0.3.1-pre.1
2. Décision opérateur qui recalibre le prompt initial
Le brainstorming de pre.001 a séparé la création de l'API Store de son implémentation PostgreSQL.
La trajectoire devient :
0.3.1 = ksp-store-api uniquement
0.3.2 = ksp-store-lib + ksp-store-postgres-lib
feature postgres par défaut
PostgreSQL de référence via tokio-postgres
Cette décision remplace pour 0.3.1 la mission combinée ksp-store-api + ksp-store-lib décrite dans le prompt de démarrage. pre.001-fix.001 réconcilie immédiatement le ROADMAP.md afin que la trajectoire globale ne conserve pas une séquence désormais fausse.
Conséquences immédiates :
aucune dépendance PostgreSQL en 0.3.1
aucun tokio-postgres dans Cargo en 0.3.1
aucun pool
aucune table
aucun SQL
aucune migration
aucun std.store
aucun ksp-store-lib
0.3.1 doit stabiliser le contrat logique suffisamment pour que 0.3.2 puisse ensuite demander :
quelle représentation PostgreSQL satisfait le mieux ce contrat ?
et non :
comment exposer les tables déjà créées ?
3. Mission recalibrée
0.3.1 introduit ksp-store-api comme modèle logique commun et API fonctionnelle backend-agnostic du niveau N1 / D1 RAW.
La crate doit posséder :
modèles objet/struct persistants communs
références durables
provenance d'acquisition
outcomes d'écriture/idempotence
queries et pagination bornées
health/readiness communs utiles
contrats/capabilities backend extensibles
format canonique de notification de disponibilité si la référence RAW est stabilisée
La façade runtime concrète Store, la sélection d'un backend compilé et l'orchestration commune appartiendront à ksp-store-lib en 0.3.2. Les consumers ordinaires jobs/workers/apps dépendront alors uniquement de ksp-store-lib, qui réexportera la surface commune nécessaire de ksp-store-api.
Elle ne possède pas :
schéma physique
rows backend
SQL
migrations
pool/connection
transactions SQL
backend selection par lecture Config
tokio-postgres
PostgreSQL/MySQL/SQLite/RocksDB/ClickHouse types
Transport
Program decoder
Materializer
Le modèle public ksp-store-api est volontairement réutilisable par toute implémentation future. Un backend peut choisir une représentation physique radicalement différente sans modifier les DTO/entités et opérations logiques consommés par l'extérieur.
4. Modèle d'extensibilité backend
4.1 Graphe durable
Le graphe cible devient :
ksp-store-api
modèles + contrats communs
|
+------------------+------------------+
| |
v v
ksp-store-lib ksp-store-postgres-lib
façade/runtime commun impl PostgreSQL
backend dispatch tokio-postgres
| ^
| feature postgres (default) ----------+
|
+-- feature mysql ------> futur ksp-store-mysql-lib
+-- autres features ----> futurs backends
Règles de dépendances :
ksp-store-lib -> ksp-store-api
ksp-store-lib[postgres] -> ksp-store-postgres-lib
ksp-store-postgres-lib -> ksp-store-api
futur ksp-store-mysql-lib -> ksp-store-api
ksp-store-postgres-lib -X-> ksp-store-lib
backend alternatif -X-> ksp-store-lib
ksp-store-lib est donc le point de consommation normal du workspace, tandis que ksp-store-api reste le contrat d'implémentation partagé entre la façade et les backends.
4.2 Features de ksp-store-lib
0.3.2 introduira au minimum :
default = [postgres]
postgres -> dépendance optionnelle ksp-store-postgres-lib
Les futures features peuvent ajouter mysql, sqlite, rocksdb, clickhouse ou tout autre backend réellement implémenté. Plusieurs features backend peuvent être compilées simultanément ; la feature décide quels backends sont disponibles dans le binaire, jamais lequel est sélectionné au runtime.
La Config décide le backend actif parmi ceux compilés. Un backend KSP connu mais absent des features du binaire doit produire une erreur distincte et stable de type STORE_BACKEND_NOT_COMPILED, sans fallback silencieux vers PostgreSQL ou un autre backend.
4.3 Config, URI et secrets
ksp-store-api, ksp-store-lib et les crates backend ne lisent jamais directement .env ni les variables KSP/KSPB. ksp-config-lib reste propriétaire des documents, placeholders, .env, provenance et sensibilité.
La configuration future suit :
std.store / profil composite
|
v
ksp-config-lib
résolution ${KSP_SECRET_*}
+ validation schema/sémantique
|
v
settings runtime ksp-store-lib
|
v
backend compilé sélectionné
|
v
crate backend privée
Règles fixées pour 0.3.2 et les futurs backends :
- utiliser une URI/DSN lorsque le moteur possède une forme URI naturelle (
postgresql://..., futurmysql://..., etc.) ; - permettre des options typées backend-specific uniquement lorsqu'elles sont réellement nécessaires et sans
serde_json::Valueopaque comme contrat runtime ; - considérer l'URI entière comme
Secretdès qu'elle peut embarquer user/password/token ou autre credential ; - obtenir les secrets via des placeholders
KSP_SECRET_*résolus par Config, avec inventaire dans.env.exampleau même delta que leur première utilisation ; - ne jamais versionner un vrai
.envni un URI/credential réel ; - ne jamais exposer URI, password, token, query secret ou chemin sensible dans
Debug, logs, erreurs ou health ; - distinguer
backend inconnudebackend KSP connu mais non compiléavant tentative de connexion ; - éviter tout fallback implicite vers
PG*,.pgpassou autre source d'environnement lue directement par le driver/backend lorsque Config a déjà fourni les settings effectifs.
La forme exacte de StoreSettings et du document std.store appartient au design de 0.3.2; 0.3.1 fixe seulement ces responsabilités et invariants.
4.4 Surface consumer
Les jobs/workers/apps ne dépendent pas directement de ksp-store-postgres-lib ni des futurs backends. Le chemin normal est :
ksp-job-* / ksp-worker-* / app
-> ksp-store-lib
-> réexporte les types API communs nécessaires
-> expose Store/open/read/write/query communs
-> dispatch vers le backend choisi par Config
Le consumer ne contient aucun #[cfg(feature = "postgres")] métier et ne branche pas sur postgres, mysql ou un nom de moteur pour lire/écrire les données.
4.5 Modèle public et modèle interne
Trois surfaces restent strictement distinctes :
ksp-store-api
RawTransaction / RawLog / provenance / queries / outcomes
= modèle objet et contrats communs à toutes les implémentations
ksp-store-lib
Store / lifecycle / dispatch / settings runtime publics communs
= façade de consommation normale
ksp-store-postgres-lib
Postgres*Row / SQL / schema / migrations / pool / statements
= implémentation privée au backend
Aucun type de row backend, handle de pool, statement préparé, migration ou nom d'objet SQL ne traverse ksp-store-lib vers ses consumers.
5. Sources KSP relues
Le gate pre.001 a relu les sources 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/007-EXECUTION_AND_POLICY.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
Les règles directement structurantes sont :
KSP-API-001..007
KSP-CONFIG-001..018
KSP-NOTIFY-001..006
KSP-STORE-001..002
KSP-DATA-001..004
KSP-PIPE-001..007
DEP-KSP-001..005
DEP-CARGO-001..007
DEP-STORE-001..008
DEP-TRANSPORT-001..005
DEP-PIPE-001..008
DEP-WORKER-001..003
DEP-JOB-001..003
Le résultat normatif principal est :
Store API possède les contrats persistants
Store API -X-> Transport/Program/Materializer
Transport -X-> Store API
conversion explicite à la composition
persist -> commit -> notification
notification != backlog
at-least-once + persistence idempotente
6. N1 / D1 RAW : définition retenue
6.1 Rôle
N1 est la couche acquisition persistée / RAW replayable.
Elle ne se limite pas à une table raw_transactions. Elle regroupe les faits d'acquisition nécessaires pour rejouer ultérieurement la normalisation générique Solana sans redemander arbitrairement la donnée au provider.
La première surface concrète 0.3.1 retient :
RawTransaction
RawTransactionObservation
RawLog
RawLogObservation
provenance commune
références durables communes
Les familles suivantes sont explicitement prévues mais reportées tant que leur acquisition/replay exact n'est pas suffisamment auditée :
RawAccount / account observation
RawBlock
RawSlot / slot update si un besoin durable distinct existe
autres familles d'acquisition réellement nécessaires
Aucun enum fermé ne doit empêcher leur ajout.
6.2 Transport n'est pas une famille RAW
Les mécanismes suivants sont des origines d'acquisition, pas des modèles persistants distincts :
HTTP JSON-RPC
WebSocket JSON-RPC
Yellowstone gRPC
provider extension
import
backfill
Interdit :
RawHttpTransaction
RawWsTransaction
RawGrpcTransaction
La même transaction logique acquise par HTTP, WS et gRPC doit converger vers un RawTransaction commun, avec plusieurs observations/provenances si nécessaire.
6.3 Transaction canonique et observation
Le contrat sépare :
RawTransaction
= fait RAW canonique source-independent et replayable
RawTransactionObservation
= fait qu'une source donnée a observé/acquis cette transaction
Exemple :
RawTransaction T
^
|
+---------------+---------------+
| | |
HTTP/Helius obs WS/Helius obs gRPC/PublicNode obs
La duplication d'observation ne duplique pas automatiquement la transaction canonique.
6.4 Raw logs
RawLog est une famille N1 distincte et n'est pas confondue avec la future décomposition CORE des logs.
Elle doit préserver l'observation de logs suffisamment fidèlement pour :
conserver l'ordre des lignes
conserver slot/signature/identité applicable
conserver le statut source nécessaire
permettre replay/inspection
permettre de relier un log à une transaction lorsqu'elle est connue
Une observation logsSubscribe peut également servir de déclencheur pour acquérir ensuite la transaction complète. Le modèle de provenance ne doit pas empêcher une lineage future :
RawLogObservation
-> déclenche acquisition transaction
RawTransactionObservation
-> RawTransaction
Cette relation causale n'est pas un orchestrateur et n'est pas obligatoirement implémentée dans 0.3.1.
6.5 Autres RAW
Le design doit permettre d'ajouter plus tard des familles distinctes sans créer un RawAnything { kind, json } universel.
Le partage se fait par composition de primitives communes :
RawAcquisitionProvenance
RawPayload
RawContentHash / idempotence key
RawDataReference
PageRequest / Page
et non par effacement des sémantiques propres à chaque famille.
7. Payload replayable
7.1 Décision de niveau API
ksp-store-api possède un payload de persistence RAW KSP, pas un payload réseau provider.
Le contrat candidat est un conteneur borné et versionné :
RawPayload
format_id
format_version
bytes
content_hash
format_id identifie un format de persistence KSP source-independent. Il ne vaut pas helius_json, yellowstone_proto ou un autre wire provider.
La conversion :
transport model
-> conversion explicite
-> RawPayload KSP
reste hors de ksp-store-api.
7.2 Pas de codec improvisé
0.3.1 ne choisit pas un codec réseau ou Solana concurrent. bincode reste interdit pour les codecs wire KSP.
Le premier format concret de transaction canonique doit pouvoir être produit par la future couche de conversion à partir des wires génériques KSP. Sa définition détaillée peut évoluer pendant 0.3.1 tant que les invariants publics restent :
source-independent
versionné
borné
lossless pour la normalisation générique couverte
Debug sans bytes
hashable/idempotent
Le Store ne prétend pas que des bytes arbitraires sans format connu sont replayables.
8. Future décomposition N1 -> niveau générique Solana
La frontière architecturale actuelle reste nommée :
RAW -> CORE -> DECODE -> SPECIALIZED
Le nom CORE n'est pas considéré comme irréversible. Une revue de nomenclature pourra être faite avant l'ouverture effective de D2 sans modifier les responsabilités déjà fixées.
Le rôle de D2 reste en revanche clair : décomposer/normaliser une transaction RAW en faits Solana génériques indépendants des decoders Program.
Le futur flux doit permettre notamment :
RawTransaction
-> transaction/message générique
-> account keys
-> instruction top-level #0
-> instruction top-level #1
-> CPI/inner instruction #1.0
-> CPI/inner instruction #1.1
-> logs/meta/balances/return data applicables
Chaque instruction/CPI doit ensuite pouvoir être traitée indépendamment :
instruction générique
-> decoder disponible ?
oui -> decode
non -> Unsupported/NotApplicable durable sans bloquer le reste
0.3.1 ne crée aucun type D2/CORE et ne dépend pas de ksp-program-api.
9. Provenance commune
La provenance candidate doit pouvoir représenter sans secret :
network/cluster
provider code
endpoint logical id optionnel
transport/protocol code
acquisition method
origin live/backfill/import/replay/repair
commitment optionnel
capture/session/filter logical ids optionnels
observed/received timestamp
source payload size/hash optionnels
Interdits :
endpoint URL
DSN
API key
token/password
payload source complet par simple diagnostic
Les codes provider/protocol/method restent ouverts et bornés ; aucun enum provider fermé n'est introduit dans Store API.
10. Identité et idempotence
10.1 Principes
L'API ne fournit pas de méthode has_* à appeler avant un write idempotent.
Le backend doit recevoir une opération unique avec ces sémantiques :
clé déjà absente
-> Inserted
même clé + même contenu canonique
-> AlreadyPresent
même clé + contenu différent
-> Conflict
Cela évite un check-then-insert race.
10.2 Transactions
La clé logique d'un RawTransaction est dérivée au minimum du réseau et de la signature canonique. Un hash du contenu canonique protège contre une collision logique avec contenu divergent.
La signature ne doit pas être représentée comme un identifiant SQL i64 dans l'API.
10.3 Observations
Chaque observation possède une clé d'idempotence déterministe fournie par le producer/composition selon un contrat documenté. Deux acquisitions légitimes distinctes peuvent donc être conservées même si elles pointent vers le même RAW.
10.4 Logs
L'identité exacte d'un RawLog sera stabilisée avec son modèle concret ; elle doit être déterministe et ne doit pas dépendre d'un primary key backend.
Aucune promesse exactly-once distribuée n'est faite.
11. API candidate
11.1 Contrats communs
ksp-store-api définit le modèle et les opérations backend-agnostic qu'une implémentation doit satisfaire. 0.3.1 ne construit pas de backend, ne sélectionne aucun moteur et n'introduit pas encore la façade runtime concrète Store.
Le backend concret implémente un contrat public d'extension, mais son modèle interne reste privé. En 0.3.2, ksp-store-lib::Store enveloppera ce contrat et deviendra la seule façade de consommation normale des jobs/workers/apps.
11.2 Object-safety et async
La future sélection runtime impose que le contrat backend puisse être stocké derrière une abstraction dynamique sans connaître le moteur concret.
La stratégie candidate est :
StoreBackend: Send + Sync
méthodes object-safe
futures boxed KSP-owned via un alias StoreFuture<'a, T>
future ksp-store-lib::Store possède Arc<dyn StoreBackend>
Cette stratégie évite une dépendance async-trait uniquement pour masquer la transformation. Le coût d'une box de future est accepté au niveau Store, dominé par l'I/O de persistence, et doit rester mesurable si un chemin futur démontre le contraire.
11.3 Capabilities
Éviter un trait de 150 méthodes. La candidate est une composition de capabilities N1 :
StoreHealth
RawTransactionStore
RawLogStore
Un contrat composite StoreBackend peut agréger les capabilities N1 nécessaires à la future façade ksp-store-lib::Store.
Les futures couches D2/D3/D4 ne sont pas ajoutées par anticipation.
11.4 Opérations atomiques métier
Aucun handle de transaction SQL/public n'est exposé.
Les invariants multi-écritures sont exprimés par des opérations logiques communes. Candidate :
persist_transaction_acquisition(transaction, observation)
record_transaction_observation(observation)
get_raw_transaction(reference)
list_raw_transactions(query, page)
list_transaction_observations(query, page)
persist_log_acquisition(raw_log, observation)
record_log_observation(observation)
get_raw_log(reference)
list_raw_logs(query, page)
list_log_observations(query, page)
health()
persist_*_acquisition signifie au contrat que le RAW et son observation réussissent atomiquement ou échouent ensemble. PostgreSQL réalisera cela avec une transaction privée en 0.3.2; un autre backend utilisera son mécanisme natif.
11.5 Outcomes
Le vocabulaire candidat :
RawWriteOutcome
Inserted
AlreadyPresent
Conflict
= Error KSP stable, pas un succès silencieux
Pour une acquisition combinée, l'outcome doit distinguer au minimum l'état du RAW et de l'observation sans révéler de clé backend.
11.6 Pagination
Le concept historique PageRequest/PageSlice est repris avec :
default = 100
maximum = 500
cursor opaque et borné
ordre déterministe par query
Le cursor est un token d'implémentation retourné par la façade et réinjecté tel quel par le consumer. Son contenu ne devient pas API et ne doit pas être utilisé comme transport d'un SQL fragment.
12. Références durables et notifications
L'ownership KSP-NOTIFY-001..006 reste à ksp-store-api.
Le candidat est une référence compacte :
RawDataReference
Transaction(RawTransactionReference)
Log(RawLogReference)
futures variantes non exhaustives
Puis un signal logique :
RawDataAvailable {
reference,
}
Le mécanisme de diffusion est hors scope.
Ordre obligatoire :
persist
commit
notify
La notification ne transporte pas le payload RAW et ne remplace jamais list_*/backlog Store.
Si les références concrètes ne sont pas assez stabilisées lors de leur tranche, le type de notification peut être reporté sans déplacer son ownership.
13. Health et diagnostics
La façade peut exposer un health commun minimal :
Unknown
Healthy
Degraded
Unhealthy
avec un backend code sûr et un code diagnostic borné si nécessaire.
Ne pas exposer dans l'API commune :
migration SQL state
pool handles
connection count détaillé par driver
server error brut
DSN
SQLSTATE arbitraire présenté comme contrat portable
Les diagnostics spécifiques à PostgreSQL appartiennent à ksp-store-postgres-lib. ksp-store-lib ne projette vers le contrat commun que les états réellement portables et sanitised.
14. Dependency graph 0.3.1
Graphe maximal par défaut :
ksp-store-api
└── ksp-core-lib
Aucune dépendance externe n'est nécessaire pour la foundation candidate :
pas de serde
pas de chrono
pas de tokio
pas de async-trait
pas de futures-util
pas de ksp-interface-lib tant qu'un type Interface réel n'est pas requis
Les timestamps persistants peuvent être représentés par un newtype KSP en unités Unix explicites plutôt que d'ajouter chrono par réflexe. Le choix exact est prouvé dans la tranche de modèle.
15. Audit historique kbot3
15.1 Surface auditée
L'archive historique a été extraite et les surfaces prescrites ont été relues, notamment :
ks-store/Cargo.toml
ks-store/README.md
ks-store/USAGE.md
ks-store/TODO.md
ks-store/src/lib.rs
ks-store/src/store.rs
ks-store/src/contracts/**
ks-store/src/postgres/**
ks-store/migrations/postgres/**
config/store.config.json
config/schemas/store.config.schema.json
ks-config/src/store.rs
docs/architecture/STORAGE_ARCHITECTURE.md
docs/guides/POSTGRES_STORAGE.md
docs/plans/V0_5_3_KS_STORE_NORMALIZATION_PLAN.md
Le Store historique couvre 16 tables N1-N3, 240 ressources SQL atomiques et 79 index attendus. Cette surface confirme l'intérêt de la séparation façade/backend, de l'idempotence et des observations, mais elle est beaucoup trop large pour 0.3.1.
15.2 Matrice d'héritage
| Concept historique | Observation kbot3 | Décision | Application KSP |
|---|---|---|---|
| séparation façade Store / PostgreSQL | PostgreSQL et sqlx::PgPool privés |
REPRENDRE | API commune séparée; façade + backend PostgreSQL reportés à 0.3.2 |
StoreOpenOptions / backend selection |
backend + serde_json::Value opaque dans Store |
REDESSINER | Config produit les settings communs; ksp-store-lib sélectionne un backend compilé et construit Store |
| health/readiness | contrat backend-neutral présent | REPRENDRE | health minimal portable dans ksp-store-api |
contracts/dto/raw.rs |
transaction canonique + observations transaction/account | REDESSINER | transaction + logs + provenance commune, sans JSON universel ni lifecycle D2/D3 |
contracts/entity/raw.rs |
rows exposant i64, JSON et timestamps backend-shaped |
REDESSINER | entités logiques sans PK SQL ni type physique |
RawTransactionStore |
has_* puis inserts séparés |
REDESSINER | write idempotent atomique sans check-then-insert |
| repository traits | capabilities async séparées | REPRENDRE | capabilities N1 séparées + façade commune |
| pagination | 100 par défaut, 500 max, cursor opaque | REPRENDRE | mêmes bornes candidates, cursor toujours opaque |
| replay contracts | filtres mêlés au processing N2/N3 | REPORTER | 0.3.1 fournit seulement lectures RAW nécessaires au futur replay |
| error contracts | erreurs Store historiques | REDESSINER | ksp_core_lib::Error/Result + codes Store stables |
| schema validation / migration bootstrap | validation stricte des objets PostgreSQL | REPORTER | responsabilité ksp-store-postgres-lib en 0.3.2 |
| migrations atomiques | ressources SQL actives nombreuses | REPORTER | aucune migration dans Store API |
| constraints/indexes | 79 index attendus | REPORTER | design physique seulement après stabilisation API |
| idempotence / uniqueness | observation keys + canonical identity | REPRENDRE | sémantique publique déterministe; mécanisme backend privé |
| raw transaction table | table physique k_sol_raw_transactions |
REPORTER | RawTransaction commun maintenant; table privée à ksp-store-postgres-lib en 0.3.2 |
| acquisition observations | transaction + account observations | REPRENDRE | concept N1 central; transaction + log initialement |
| processing ledger | couvre N2/N3 processing | REPORTER | appartient aux futures couches de processing, pas N1 foundation |
| CORE tables | transaction, keys, instructions, CPI, logs, balances, return data | REPORTER | future couche D2, aucune surface en 0.3.1 |
| DECODE coverage/events | contrats decoder/materializer | REPORTER | future D3 |
| materialization journal | k_sol_mat_outputs |
REPORTER | future D3 |
| maintenance truncate/drop | scripts destructifs dédiés | REJETER | aucune API runtime générique destructive Store |
| Config Store | backend + options JSON historiques | REDESSINER | Config reste owner; settings Store/URI secrets adaptés vers ksp-store-lib en 0.3.2 |
| runtime diagnostics | résumés sanitised mais backend riches | REDESSINER | health portable dans API; détails backend privés |
16. Audit PostgreSQL et driver de référence futur
16.1 Décision
Le choix opérateur est fixé pour la version suivante :
ksp-store-lib
façade/runtime commun
feature postgres = feature par défaut
feature postgres -> ksp-store-postgres-lib
ksp-store-postgres-lib
backend officiel de référence = PostgreSQL
driver interne = tokio-postgres
Ce choix n'ajoute aucune dependency à 0.3.1.
16.2 État externe audité au 28 août 2026
Sources primaires actuelles consultées : documentation PostgreSQL et documentation/package tokio-postgres.
Résultats :
PostgreSQL stable courant : 18.6, publié le 13 août 2026
tokio-postgres courant : 0.7.18, publié le 12 juin 2026
edition tokio-postgres : Rust 2024
MSRV tokio-postgres : Rust 1.85
runtime async : Tokio
prepared statements : supportés
transactions / isolation : supportées
COPY in/out : supporté
pipelining : supporté
TLS : connector externe, à choisir explicitement en 0.3.2
tokio-postgres::Config peut être construit et renseigné programmaticalement. 0.3.2 devra éviter les chemins de configuration implicites : l'URI/les options effectives viennent de ksp-config-lib via les settings publics de ksp-store-lib, puis sont converties vers le backend PostgreSQL sans lecture directe de .env, PG* ou .pgpass.
16.3 SQLx
SQLx 0.9.0 a été réaudité comme alternative mais n'est plus retenu après décision opérateur.
La comparaison a néanmoins confirmé l'intérêt d'éviter dans KSP les defaults de connexion influencés par PG*/.pgpass lorsque le backend peut être construit explicitement depuis Config.
La performance ne constitue pas à elle seule la raison du choix : 0.3.2 devra optimiser les vrais chemins KSP avec prepared statements, batching/COPY lorsque justifié, transactions et indexes adaptés.
17. Contrat attendu de 0.3.2 sans le concevoir physiquement ici
0.3.2 introduira deux crates dans la même release :
ksp-store-lib
ksp-store-postgres-lib
ksp-store-lib devra :
dépendre de ksp-store-api
réexporter la surface API commune nécessaire aux consumers
exposer la façade Store et son lifecycle
posséder la sélection/dispatch des backends compilés
activer postgres par défaut
importer ksp-store-postgres-lib seulement sous feature postgres
accepter les settings effectifs fournis par Config
rejeter distinctement un backend connu mais non compilé
ne jamais exposer les types internes d'un backend
ksp-store-postgres-lib devra implémenter le même modèle objet et les mêmes contrats de ksp-store-api et pourra créer librement :
PostgresStoreBackend
Postgres*Row privés
migrations
schema version
prepared statements
indexes
pool
transaction handles privés
mapping Rust API <-> PostgreSQL
tokio-postgres
Les consumers jobs/workers/apps dépendront uniquement de ksp-store-lib, avec la feature par défaut ou une sélection explicite de features. Les crates backend alternatives dépendront de ksp-store-api, pas de ksp-store-lib.
La compatibilité PostgreSQL devra être testée par round-trip des modèles API et par introspection/validation du schema réel.
18. Sorties PostgreSQL du prompt initial explicitement déplacées
Le prompt de démarrage demandait encore à pre.001 un schéma PostgreSQL candidat, une migration policy et un gate PostgreSQL live parce que 0.3.1 devait initialement contenir API et implémentation. La décision de split rend ces sorties prématurées.
Elles sont donc classées ainsi :
| Sortie initialement demandée | Décision pre.001 |
Release propriétaire |
|---|---|---|
| tables/colonnes/PK/FK/indexes RAW | REPORTER | 0.3.2 ksp-store-postgres-lib |
mapping u64/bytes/timestamps vers PostgreSQL |
REPORTER | 0.3.2 |
| migration layout/version/checksum | REPORTER | 0.3.2 |
| schema introspection/conformance | REPORTER | 0.3.2 |
| pool/TLS/timeouts | REPORTER | 0.3.2 |
| PostgreSQL live gate | REPORTER | 0.3.2 |
| SQL injection/statement policy exécutable | REPORTER | 0.3.2 |
Les invariants API qui contraignent déjà ce futur schéma restent fixés maintenant :
identités logiques non dépendantes d'une PK SQL
idempotence Inserted/AlreadyPresent/Conflict
atomicité RAW + observation
pagination bornée
payload versionné et borné
provenance sans secret
round-trip exact du modèle objet commun
Aucun nom de table candidat n'est donc produit par 0.3.1-pre.001. C'est une conséquence volontaire du split, pas une omission du gate.
La trajectoire roadmap corrigée est :
0.3.1 ksp-store-api RAW/observations
0.3.2 ksp-store-lib + ksp-store-postgres-lib
0.3.3 wires Interface nécessaires à l'acquisition/normalisation future
0.3.4 ksp-job-api + premier backfill
0.3.5 application backfill/inspection RAW
19. Threat model 0.3.1
| Menace | Réponse de design |
|---|---|
| payload hostile trop grand | bornes à la construction des contrats RAW avant persistence |
raw payload leak via Debug |
implémentations Debug manuelles/redacted pour conteneurs sensibles |
| secret provider/endpoint | provenance ne contient que des ids/codes sûrs, jamais URL/credential |
| duplicate race | write idempotent atomique, jamais has_* comme précondition |
| même clé / contenu divergent | conflit explicite, pas d'overwrite silencieux |
| partial RAW + observation | opération persist_*_acquisition atomique au contrat |
| cursor hostile | taille/limit bornées; cursor opaque non interprété par consumer |
| query non bornée | aucune liste publique sans PageRequest borné |
| backend leak | aucun type driver/row/table/SQL dans la façade |
| backend error leak | mapping vers erreurs KSP sûres; source externe auditée avant chaînage |
| closed-world backend | contrat implémentable hors ksp-store-lib |
| closed-world RAW family | types/familles extensibles sans JSON fourre-tout |
| cross-backend mismatch | conformance suite commune sur chaque implémentation |
| scope creep D2/D3/D4 | aucun type CORE/DECODE/SPECIALIZED dans 0.3.1 |
Les menaces DSN/SQL injection/schema drift/migrations restent documentées pour 0.3.2, où elles deviennent exécutables. Elles ne justifient pas des types SQL dans l'API.
20. Stratégie de tests 0.3.1
Prévoir :
unit tests module-local
public API canaries crate-root
external backend canary
object-safe backend contract canary
manifest/dependency firewall
exact public export inventory
exact production module inventory
bounds payload/provenance/cursor
Debug/redaction tests
idempotence outcome semantics
transaction/log identity validation
atomic-operation contract fake backend
pagination bounds
notification reference contract si introduit
release completeness
cargo tree -p ksp-store-api --edges normal
cargo tree --duplicates
Le backend externe canary doit implémenter le contrat avec une petite implémentation mémoire de test située hors des modules de production. Il prouve :
aucune dépendance à ksp-store-lib
aucune connaissance PostgreSQL
implémentation des mêmes capabilities API
round-trip via le contrat backend commun
Aucun PostgreSQL live test n'appartient à 0.3.1 puisque le backend PostgreSQL n'existe pas encore.
21. Ownership
| Concept | Owner | Visibilité | Introduction | Raison |
|---|---|---|---|---|
RawTransaction |
ksp-store-api |
public | 0.3.1 |
modèle persistant commun |
RawTransactionObservation |
ksp-store-api |
public | 0.3.1 |
provenance/acquisition distincte du RAW |
RawLog |
ksp-store-api |
public | 0.3.1 |
seconde famille N1 explicitement demandée |
RawLogObservation |
ksp-store-api |
public | 0.3.1 |
provenance logs |
RawPayload |
ksp-store-api |
public | 0.3.1 |
contrat persistant replayable versionné |
| RAW references | ksp-store-api |
public | 0.3.1 |
reads, notification, lineage |
| write outcomes | ksp-store-api |
public | 0.3.1 |
sémantique idempotente commune |
| query/page | ksp-store-api |
public | 0.3.1 |
backlog/replay backend-agnostic |
| health portable | ksp-store-api |
public | 0.3.1 |
consumer commun |
| backend extension trait | ksp-store-api |
public | 0.3.1 |
implémentation externe réelle |
Store facade |
ksp-store-lib |
public | 0.3.2 |
point de consommation commun |
| backend dispatch/settings | ksp-store-lib |
public/privé selon contrat | 0.3.2 |
features disponibles + sélection Config |
| PostgreSQL settings internes | ksp-store-postgres-lib |
privé ou constructor-boundary | 0.3.2 |
construction du backend de référence |
| PostgreSQL rows | ksp-store-postgres-lib |
privé | 0.3.2 |
mapping physique |
| pool/connection | ksp-store-postgres-lib |
privé | 0.3.2 |
détail runtime |
| SQL/statements | ksp-store-postgres-lib |
privé | 0.3.2 |
détail backend |
| migrations/schema | ksp-store-postgres-lib |
privé/opérateur | 0.3.2 |
détail backend |
| transport -> RAW conversion | composition/pipeline futur | privé/réutilisable selon besoin | release acquisition | DEP-KSP-003 |
| RAW -> D2 normalization | future pipeline générique | hors 0.3.1 |
série suivante | aucune dépendance Program |
| notification mechanism | futur host/runtime | hors API de diffusion | ultérieur | Store API possède seulement le format |
22. Hors scope strict 0.3.1
ksp-store-lib
PostgreSQL runtime
tokio-postgres dependency
pool/TLS PostgreSQL
SQL/tables/indexes/migrations
std.store Config
backend MySQL/SQLite/Oracle/RocksDB/ClickHouse
Transport acquisition runtime
conversion Transport -> RAW fonctionnelle
D2/CORE structs et persistence
RAW -> D2 normalizer
Program decode
Materializer
processing ledger
worker/job/backfill
application Store/RAW
notification transport concret
retention/archive/purge lifecycle
truncate/drop/maintenance API
23. Prévision souple recalibrée 0.3.1
Chaque tranche vise environ 15–20 minutes de travail effectif.
pre.001 — Audit, modèle N1 et split API/backend
Base, règles, architecture, audit kbot3, audit PostgreSQL/driver futur, RAW transactions/logs, ownership, API candidate, threat model, tests et sizing.
pre.002 — Scaffold ksp-store-api
Créer uniquement la crate API, manifest Core-only, façade crate-root et documentation initiale. Aucun modèle fonctionnel lourd.
pre.003 — Primitives RAW communes + transaction
Introduire payload/reference/provenance/idempotence/timestamps bornés puis RawTransaction et son observation.
pre.004 — RAW logs + extensibilité N1
Introduire RawLog/observation, vérifier ordering/identity/bounds et verrouiller l'absence de type RAW fourre-tout.
pre.005 — Capabilities backend extensibles
Implémenter les contrats object-safe et l'external backend canary, sans façade runtime Store et sans runtime DB. La façade commune appartient à ksp-store-lib en 0.3.2.
pre.006 — Queries, pagination, outcomes et notification reference
Finaliser reads/list/backlog bornés, atomic acquisition contract et référence de notification si suffisamment stable.
pre.007 — Adversarial/API hardening + completeness
Payload/cursor/provenance hostile, Debug, external backend, exact exports/modules, dependency firewall et scope négatif D2/D3/D4.
pre.008 — Gate technique final
Workspace complet, tests Store API, graphes Cargo. Aucun développement fonctionnel nouveau.
pre.009 — Réconciliation documentaire finale
README/USAGE, plan, validation et références durables réellement concernées. Aucun CHANGELOG.md, ROADMAP.md ni prompt suivant.
pre.010 — Préparation de publication minimale
Uniquement :
Cargo.toml
CHANGELOG.md
ROADMAP.md
prompts/021-V0_3_2_START_PROMPT.md
delta pre.010
Le prompt 0.3.2 ouvre ensemble ksp-store-lib et ksp-store-postgres-lib, avec feature postgres par défaut et tokio-postgres strictement dans la crate backend.
rel.001 — Publication stable
Mécanique de publication uniquement.
La release reste estimée clôturable dans une session si les tranches conservent cette granularité et si aucun codec/normalizer D2 n'est tiré dans le scope.
24. Trajectoire 0.3.x résultante
La prévision durable devient, sous réserve des gates de chaque release :
0.3.1 ksp-store-api / N1 RAW contract
0.3.2 ksp-store-lib + ksp-store-postgres-lib / PostgreSQL reference via tokio-postgres
0.3.3 generic Interface/wire additions nécessaires à acquisition/normalisation
0.3.4 ksp-job-api + premier backfill RAW concret
0.3.5 application backfill/inspection RAW
ensuite worker/service live RAW avant ouverture D2
Cette renumérotation remplace la prévision 0.3.1..0.3.4 de la base v0.2.14; pre.001-fix.001 l'écrit immédiatement dans le ROADMAP.md pour éviter de poursuivre avec une trajectoire fausse.
25. Critères de fermeture de 0.3.1
La stable 0.3.1 est prête seulement si :
ksp-store-api existe seule dans le domaine Store
modèle objet RAW commun stable
RawTransaction + observations stables
RawLog + observations stables
future extension N1 non bloquée
contrats backend communs stables
backend externe implémentable sans ksp-store-lib
aucun type backend/SQL public
queries/pagination bornées
idempotence/conflict semantics explicites
atomic acquisition contract explicite
références durables stables
notification format introduit ou reporté explicitement
aucune dépendance PostgreSQL
aucune surface D2/D3/D4
workspace et graphes entièrement verts
prompt `0.3.2` cohérent avec ksp-store-lib + ksp-store-postgres-lib + tokio-postgres