21 KiB
Validation 0.3.1 — Store API RAW foundation
1. Objet
Cette matrice est ouverte par 0.3.1-pre.001, corrigée par pre.001-fix.001 puis recalibrée par pre.001-fix.002. Elle valide ksp-store-api uniquement. La façade/runtime commune ksp-store-lib et l'implémentation PostgreSQL séparée ksp-store-postgres-lib sont réunies dans 0.3.2.
Le scope concret N1 certain est :
RawTransaction + observation
provenance/références/outcomes/queries communs
contrats/capabilities backend externes
cycle de rétention logique + tombstone
pre.004 prouve la convergence de RawAccountState/observation entre HTTP/WS/gRPC sous admission stricte bytes complets + slot. TransactionStatusObservation reste différé : snapshot HTTP, transition WS et update Yellowstone ne sont pas encore un fait unique. Les notifications logs/slot/vote restent event-only candidates, avec ownership Interface préféré lorsqu'elles ne sont pas persistées.
2. Gate pre.001
| Critère | Statut | Preuve / décision |
|---|---|---|
base stable 0.2.14 |
PASS | Cargo 0.2.14, rel.001 et prompt 020 présents |
| baseline opérateur | PASS | audits/check/Clippy fournis verts ; validation tests déclarée OK |
| archive kbot3 + kbot2 historique | PASS | kbot3 extraite ; olddocs/archivekbot2 audité pour lifecycle/replay |
| règles Store/API relues | PASS | règles KSP/Dependencies/Workflow prescrites relues |
| split version | PASS | 0.3.1 = Store API, 0.3.2 = Store lib + PostgreSQL lib |
dependency graph 0.3.1 |
PASS | cible Core-only |
| modèle backend commun | PASS | API object/struct commune, rows backend privées |
| admission multi-source | PASS | même modèle seulement si HTTP/WS/gRPC satisfont intégralement la même sémantique |
RawTransaction |
PASS | premier modèle persistant certain |
| logs dans transaction | PASS | restent dans RawTransaction, extraction seulement en N2 STRUCTURAL |
| logsSubscribe | REPORTÉ | event-only candidat ; pas de RawLog Store persistant par défaut |
| account state | PRÉVU | modèle/observation à figer après matrice de compatibilité |
| transaction status | PRÉVU | observation/event à figer si sémantique commune prouvée |
| slot/vote | TODO | event-only candidats ; ownership Interface à auditer |
| RawBlock | IDEA | non persisté par défaut ; getBlock sert de conteneur d'acquisition |
| Yellowstone Entry | REJETÉ | aucun replay/decomposition/event métier justifiant un modèle Store |
| frontière Interface/Store | PASS | persistent/replay -> Store API ; event-only partagé -> Interface préférentiel |
| N2 nomenclature | PASS | CORE remplacé par nom de travail STRUCTURAL |
| pipeline non linéaire | PASS | toutes les familles N1 ne sont pas forcées N1->N2->N3->N4 |
| processing proof | PASS | futur ledger stage+processor/version+input hash ; processed: bool insuffisant |
| retention lifecycle | PASS | Full/Compacted/Archived/Purged redessiné backend-agnostic |
| tombstone anti-rebackfill | PASS | identité/hash/slot minimal conservé après purge ; backfill forcé distinct |
| notification ownership runtime | PASS | Store ne possède aucun event bus/scheduler/DB notify |
| schema/migrations PostgreSQL | REPORTÉ | responsabilité ksp-store-postgres-lib 0.3.2 |
| D2/N3/N4 persistence | ABSENT | hors 0.3.1 |
| threat model | PASS | source mismatch, purge prématurée, stale processing, backend/event leaks couverts |
| sizing | PASS | dix prereleases courtes + lanes fermeture séparées |
3. Décisions structurelles à prouver par le code
| Contrat | Décision pre.001-fix.002 |
Gate futur |
|---|---|---|
crate ksp-store-api |
seule crate Store créée en 0.3.1 |
pre.002 |
| dépendance normale | ksp-core-lib uniquement par défaut |
pre.002 |
RawPayload |
KSP-owned, source-independent, versionné, borné, Debug sans bytes | pre.003 |
RawTransaction |
objet persistant commun uniquement depuis une source complète | pre.003 |
RawTransactionObservation |
acquisition/provenance séparée du RAW | pre.003 |
transaction logMessages |
partie du RAW transactionnel | pre.003 |
| logs structuraux | extraction N2 STRUCTURAL future, jamais RawLog N1 distinct |
canari négatif pre.003/007 |
RawAccountState/observation |
modèle prévu si HTTP/WS/gRPC convergent sans perte | pre.004 |
TransactionStatusObservation |
modèle prévu si surfaces status convergent | pre.004 |
| logs/slot/vote event-only | ne créent aucune capability Store par défaut | pre.004/007 |
| Interface vs Store | event-only partagé -> Interface ; persistent/replay -> Store API | pre.004/007 |
| model vs capability | un modèle API n'oblige pas tous les backends à le persister | pre.005 |
| capabilities | read/write fines et object-safe | pre.005 |
| transaction handle | aucun handle SQL/backend public | pre.005 |
| atomic acquisition | méthode métier RAW + observation all-or-nothing | pre.005/006 |
| write outcome | Inserted / AlreadyPresent; divergence = Err Conflict |
pre.006 |
| page/cursor | default 100, max 500, cursor opaque borné | pre.006 |
RawRetentionState |
logique Full/Compacted/Archived/Purged, sans détail physique |
pre.006 |
| tombstone | identité/hash/slot minimal durable après purge | pre.006 |
| backfill normal après purge | skip distinct | pre.006 |
| force rehydrate | chemin explicite distinct, jamais fallback automatique | pre.006 |
| processing evidence | futur ledger version-aware, jamais un bool unique | boundary pre.006/007 |
façade runtime Store |
reportée à ksp-store-lib, hors 0.3.1 |
0.3.2 |
4. Dependency firewall final attendu
Le graphe final 0.3.1 doit rester :
ksp-store-api
└── ksp-core-lib
└── solana-pubkey
Interdits par défaut dans Store API :
ksp-store-lib
ksp-onchain-transport-lib
ksp-offchain-transport-lib
ksp-interface-lib sans usage de type réel
ksp-program-api
ksp-program-lib
ksp-materializer-api
ksp-config-lib
ksp-logging-lib
ksp-wallet-lib
tokio-postgres
sqlx
serde / serde_json
chrono
tokio
async-trait
Tauri
Toute divergence exige un usage public réel et une révision du plan.
5. Matrice N1 initiale
| Famille / fait | Classification actuelle | Persistence Store | N2 attendu | Action 0.3.1 |
|---|---|---|---|---|
| transaction complète | N1 RAW | oui | STRUCTURAL oui | implémenter modèle + observation |
| logs contenus dans transaction | partie de RawTransaction | via transaction | STRUCTURAL oui | préserver lossless, ne pas dupliquer en RawLog |
| account state complet | N1 RAW | oui à terme | pas démontré | modèle + observation matérialisés en pre.004 |
| transaction status | familles distinctes | non figée | non | différer : snapshot HTTP != transition WS != update Yellowstone |
logsSubscribe notification |
event-only candidat | non par défaut | non | ownership Interface/worker à figer |
| slot/root/slotsUpdates | event-only candidat | non | non | TODO use-case + compatibilité |
| vote | event-only candidat | non | non | TODO seulement si forme commune utile |
| block complet | acquisition container | non par défaut | — | IDEA uniquement ; extraire transactions plutôt que stocker le bloc |
| Yellowstone Entry | transport-only | non | — | explicitement non retenu |
6. Frontière N1 -> N2 STRUCTURAL
0.3.1 doit préserver sans implémenter :
RawTransaction
-> StructuralTransaction/message
-> account keys
-> top-level instructions
-> CPI/inner instructions
-> logs/meta/balances/return data
-> traitement individuel ultérieur
N2 est nommé STRUCTURAL parce qu'il décrit une décomposition générique Solana, pas un domaine métier « Core ».
Canaris :
ksp-store-api -X-> ksp-program-api
RawTransaction logMessages -X-> entité RawLog persistante séparée
une erreur/absence future de decoder -X-> blocage des autres instructions
Toutes les familles N1 ne sont pas obligées de posséder un N2. RawAccountState peut par exemple aller directement vers une future étape de decode si aucune décomposition structurelle utile n'est identifiée.
7. Extensibilité backend
Le canari externe doit démontrer :
crate/test backend externe
-> dépend de ksp-store-api
-> définit son propre backend mémoire
-> implémente les contrats/capabilities publics
-X-> ksp-store-lib
-X-> PostgreSQL
0.3.2 ajoutera ensuite la façade de consommation ksp-store-lib. Le backend officiel ksp-store-postgres-lib devra satisfaire la même suite de conformance API.
8. Threat/API gates futurs
| Gate | Attendu | Statut initial |
|---|---|---|
| oversized RAW payload | rejet avant allocation pathologique | pre.003 |
| payload Debug | aucun bytes brut | pre.003 |
| partial source -> RawTransaction | interdit ; contrat complet exigé | pre.003/004 |
| HTTP/WS/gRPC semantic mismatch | détecté par admission matrix | pre.004 PASS |
| account bytes partiels/parsés | refusés avant RawAccountState |
pre.004 PASS |
| account sans slot durable | refusé comme état persistant | pre.004 PASS |
| account data Debug | aucun bytes brut | pre.004 PASS |
| status surfaces artificiellement fusionnées | aucun modèle commun prématuré | pre.004 PASS |
| duplicate same content | AlreadyPresent |
pre.006 |
| duplicate divergent content | Conflict stable | pre.006 |
| partial transaction+observation | interdit par atomic acquisition | pre.005 PASS |
| event-only -> Store capability | absent par défaut | pre.004/007 |
| Interface/Store duplicate model | absent | pre.007 |
| page limit 0/>500 | rejet | pre.006 |
| SQL/backend cursor leak | absent | pre.006/007 |
| external backend | implémente API sans Store lib | pre.005 PASS |
processing bool comme vérité |
absent ; future preuve version-aware documentée | pre.006/007 |
| purge sans policy/evidence | impossible par contrat | pre.006/007 |
| tombstone supprimé avec payload | interdit | pre.006 |
| rebackfill normal après purge | skip | pre.006 |
| force rehydrate implicite | interdit | pre.006 |
| N2/N3/N4 creep | aucune surface | pre.007 |
8.1 Matérialisation pre.003
La tranche implémente et couvre localement par canaris source/audit :
RawNetworkId
RawTransactionSignature [u8; 64]
RawTransactionReference
RawFormatId
RawContentHash [u8; 32]
RawObservationKey [u8; 32]
RawTimestamp
RawAcquisitionOrigin
RawProvenanceCode
RawAcquisitionProvenance
RawPayload
RawTransaction
RawTransactionObservation
Gates matérialisés :
Core-only dependency firewall conservé
payload KSP source-independent, non vide, version > 0
payload maximum Store = 16 MiB
source payload metadata maximum = 64 MiB
Debug RawPayload ne rend jamais les bytes
signature/observation key/hash ne dépendent d'aucune PK backend
provenance sans URL/source payload
observed_at <= received_at
logs transactionnels restent dans le payload RawTransaction
aucun RawLog/N2 STRUCTURAL/backend/runtime ajouté
La complétude sémantique d'une source HTTP/WS/gRPC vers le format canonique n'est pas simulée dans Store API : elle reste le gate d'admission/conversion de pre.004. pre.003 exige seulement qu'un RawTransaction reçoive un RawPayload déjà canonique complet selon son format KSP déclaré.
8.2 Matérialisation pre.004
La tranche ajoute :
MAX_RAW_ACCOUNT_DATA_BYTES
RawAccountStateReference
RawAccountState
RawAccountObservation
Invariants vérifiés par modèle/canaris :
référence = network + pubkey + slot + canonical state hash
account data complet <= 16 MiB
empty account data autorisé
Debug RawAccountState ne rend jamais les bytes
write_version/transaction_signature/is_startup restent observation-only optionnels
HTTP/WS/gRPC source details n'entrent pas dans RawAccountState
aucun TransactionStatusObservation artificiel
aucun RawLogNotification/RawSlotEvent/RawVoteEvent/RawBlock/YellowstoneEntry public
Matrice d'admission validée architecturalement :
getAccountInfo/getMultipleAccounts -> oui avec bytes complets
getProgramAccounts -> contexte obligatoire
accountSubscribe -> oui avec bytes complets
programSubscribe -> contexte obligatoire
Yellowstone Account -> aucun accounts_data_slice
jsonParsed/dataSlice/bare program -> non
La conversion source -> modèle reste hors ksp-store-api; la crate ne dépend toujours que de ksp-core-lib.
8.3 Matérialisation pre.005
La tranche ajoute uniquement des contracts de capability backend-agnostic :
StoreApiFuture<'a, T>
RawTransactionRead
RawTransactionWrite
RawTransactionObservationRead
RawTransactionObservationWrite
RawAccountStateRead
RawAccountStateWrite
RawAccountObservationRead
RawAccountObservationWrite
Gates matérialisés :
traits Send + Sync et dyn-compatible
aucune dépendance async-trait/tokio/futures-util ajoutée
backend externe implémentable avec std + ksp-store-api seulement
aucun trait StoreBackend monolithique
aucune façade runtime Store
aucun type Config/backend/SQL public
persist_raw_transaction_acquisition = transaction + observation atomiques
persist_raw_account_acquisition = account state + observation atomiques
record_*_observation = acquisition supplémentaire sans retransmettre le RAW
get_* = référence/observation key backend-independent
write success/failure seulement en pre.005
outcomes/idempotence/conflict détaillés réservés à pre.006
Le canari tests/external_backend.rs définit un backend mémoire externe qui implémente les huit traits sans dépendre de ksp-store-lib, PostgreSQL ou d'un runtime async. Il prouve également que chaque capability est utilisable derrière dyn Trait.
Aucune implémentation de persistence n'est fournie par ksp-store-api; les futures concrètes du canari ne servent qu'à vérifier le contrat d'extension.
9. Gates de fermeture prévus
Gate technique final pre.008
Commandes de référence :
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.1
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-store-api
cargo test -p ksp-logging-lib --test ownership
cargo test --workspace
cargo tree -p ksp-store-api --edges normal
cargo tree --duplicates
Réconciliation documentaire pre.009
Doit fermer :
crates/ksp-store-api/README.md
crates/ksp-store-api/USAGE.md
plan 022
validation 018
indexes/références durables concernées
Sans CHANGELOG.md, ROADMAP.md ni prompt suivant.
Préparation de publication pre.010
Doit rester limitée à :
Cargo.toml
CHANGELOG.md
ROADMAP.md
prompts/021-V0_3_2_START_PROMPT.md
delta pre.010
Le ROADMAP.md est réconcilié par pre.001-fix.001 puis pre.001-fix.002; pre.010 ne doit plus avoir à réparer la taxonomie N1/N2 ni le split backend.
10. PostgreSQL reporté à 0.3.2
Aucun gate PostgreSQL live n'est demandé à 0.3.1.
Le prochain prompt devra transformer les invariants API en façade commune + backend de référence et prévoir :
ksp-store-lib
-> façade Store commune
-> réexports utiles de ksp-store-api
-> feature postgres par défaut
-> dispatch backend selon Config
-> erreur backend connu mais non compilé
ksp-store-postgres-lib
-> tokio-postgres
-> pool/TLS audités
-> migrations KSP-owned
-> schema conformance
-> write/read round-trip des modèles API
-> idempotence/race
-> atomic rollback
-> pagination
Config
-> std.store
-> URI/DSN backend lorsque naturel
-> secrets ${KSP_SECRET_*} / .env owned par ksp-config-lib
-> aucun vrai secret versionné
sécurité
-> URI/DSN/credentials redacted
-> aucune lecture directe env/.env par Store ou backend
-> PostgreSQL réel opt-in puis gate final obligatoire
11. État initial des tranches
| Tranche | Objet | État |
|---|---|---|
pre.001 |
audit/design/taxonomie/split | PRÊT après gate local |
pre.002 |
scaffold + taxonomie Store API | À FAIRE |
pre.003 |
primitives + RawTransaction | À FAIRE |
pre.004 |
admission matrix + account/status models | PRÊT après gate local |
pre.005 |
backend contracts/capabilities | PRÊT après gate local |
pre.006 |
queries/outcomes/retention/tombstone | À FAIRE |
pre.007 |
boundary/adversarial/completeness | À FAIRE |
pre.008 |
gate technique final | À FAIRE |
pre.009 |
réconciliation documentaire | À FAIRE |
pre.010 |
préparation publication | À FAIRE |
rel.001 |
stable | À FAIRE |