Files
khadhroony-solana-project/docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md
2026-08-30 09:22:53 +02:00

32 KiB

Validation 0.3.3 — Store/PostgreSQL RawTransaction vertical slice

1. Objet

Cette validation accompagne :

0.3.3 — Store/PostgreSQL RawTransaction vertical slice

Elle démarre en 0.3.3-pre.001 comme matrice de preuve. Les gates opérateur de pre.001 et pre.002 sont verts. Les lignes non encore implémentées restent explicitement À FAIRE; elles ne sont pas présentées comme acquises.

2. Baseline stable

Preuve Attendu pre.001 Statut
Base de travail archive/tag v0.3.2 PASS
workspace package version avant overlay 0.3.2 PASS
Gate opérateur 0.3.2 audits/check/clippy/tests Store+Config/no-default-features propres PASS
PostgreSQL live métier 0.3.2 absent ; seule fondation opt-in existe PASS
Prompt release prompts/022-V0_3_3_START_PROMPT.md PASS
Archive historique kbot3 audit ciblé uniquement PASS

2.1 Inventaire exact 0.3.2

ksp-store-api             modules=capability,error,model                       root pub use=60
ksp-store-lib             modules=constants,error,health,settings,store       root pub use=84, default feature=postgres
ksp-store-postgres-lib    modules=constants,error,health,migration,runtime    root pub use=7
V000__bootstrap.sql        SHA-256=d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450
std.store format_version   1
std.store profiles         devnet/devnet, mainnet/mainnet-beta, testnet/testnet
foundation live            PASS PostgreSQL 17 en pre.008 et pre.010

Le test live est #[ignore] dans les gates ordinaires mais sa preuve réelle antérieure est documentée dans 019-V0_3_2_STORE_POSTGRES_FOUNDATION.md.

3. Scope exact des capacités

Capacité Backend PostgreSQL Façade Store Preuve finale
RawTransactionRead À FAIRE À FAIRE unit + integration + live
RawTransactionWrite À FAIRE À FAIRE unit + concurrency live
RawTransactionObservationRead À FAIRE À FAIRE unit + live
RawTransactionObservationWrite À FAIRE À FAIRE unit + concurrency live
RawTransactionRetentionRead À FAIRE À FAIRE unit + live
RawTransactionRetentionWrite À FAIRE À FAIRE unit + race live

Aucune capacité RawAccountState, structurale N2, job ou worker n'est admise dans cette matrice.

3.1 Matrice RawTransactionRead

Axe Preuve/attendu
input reference pour get; query pour list
invariants pré-I/O network exact; cursor lié à query
transaction SQL aucune; statement cohérent
rows touchées transaction + archive pour get; index transaction pour list
idempotence N/A
conflit N/A; corruption != conflict métier
absence/not-found get None; list vide
error mapping query/wrong-network/data/query-failed sûrs
concurrence statement snapshot; aucun snapshot inter-pages
test déterministe full/archive/purged, u64 max, ranges, cursor hostile
test PostgreSQL live get exact + pages multi-slot/ties dans deux directions

3.2 Matrice RawTransactionWrite

Axe Preuve/attendu
input transaction + observation + acquisition mode
invariants pré-I/O deux networks exacts; observation reference = canonical reference
transaction SQL une transaction atomique
rows touchées canonical + observation + archive si état existant Archived
idempotence contenu exact identique -> AlreadyPresent
conflit divergence même signature -> ERROR_CODE_RAW_CONFLICT
absence/not-found insert; Purged Normal compatible -> SkippedPurged/NotRecorded
error mapping API model/conflict; physical write/data sûrs
concurrence unique insert + FOR UPDATE du gagnant
test déterministe equality/conflict/tombstone/modes/redaction
test PostgreSQL live identical/divergent concurrent + rollback + force

3.3 Matrice RawTransactionObservationRead

Axe Preuve/attendu
input observation key
invariants pré-I/O key API valide; database network déjà bound
transaction SQL aucune
rows touchées observation
idempotence N/A
conflit N/A
absence/not-found None
error mapping stored-row invalid/query-failed sûrs
concurrence observation immuable, statement snapshot
test déterministe provenance complète/optionnelle + hostile row
test PostgreSQL live observation round-trip exact

3.4 Matrice RawTransactionObservationWrite

Axe Preuve/attendu
input observation
invariants pré-I/O observation transaction network exact
transaction SQL oui
rows touchées canonical verrouillé + observation
idempotence same key + fields identical -> AlreadyPresent
conflit same key + divergence -> ERROR_CODE_RAW_CONFLICT
absence/not-found canonical absent -> safe not-found; Purged -> NotRecorded
error mapping provenance/conflict API + not-found/write sûrs
concurrence canonical FOR UPDATE + unique observation key
test déterministe equality/missing/purged/error canaries
test PostgreSQL live identical/divergent observation races

3.5 Matrice RawTransactionRetentionRead

Axe Preuve/attendu
input transaction reference
invariants pré-I/O network exact
transaction SQL aucune
rows touchées canonical metadata
idempotence N/A
conflit N/A
absence/not-found state unknown -> None; tombstone only Purged
error mapping wrong-network/stored-metadata invalid sûrs
concurrence état committé par statement
test déterministe Full/Archived/Purged + tombstone minimal
test PostgreSQL live reads après chaque transition

3.6 Matrice RawTransactionRetentionWrite

Axe Preuve/attendu
input retention transition
invariants pré-I/O network exact; Compacted non supporté rejeté avant pool
transaction SQL oui
rows touchées canonical + archive
idempotence current == target -> AlreadyAtTarget
conflit expected perdu -> ExpectedStateMismatch
absence/not-found unknown reference -> safe not-found
error mapping invalid transition API; unsupported/physical write sûrs
concurrence FOR UPDATE canonique
test déterministe transition matrix + Compacted unsupported
test PostgreSQL live transition/purge/write/force races

4. Design physique V001

Élément Décision pre.001 Statut
Migration V001 embedded, après généralisation du moteur V000 PASS design
Database identity singleton ksp_store_identity PASS design
Réseau un réseau exact par base V001 PASS design
Transaction key signature BYTEA(64) logique PASS design
Observation key BYTEA(32) PASS design
Slot NUMERIC(20,0) ; aucun narrowing u64 PASS design
Format version BIGINT, check domaine u32 non nul PASS design
Timestamp BIGINT, check borne RawTimestamp PASS design
Payload BYTEA, 1..=16 MiB PASS design
Archive relation dédiée hors index hot-path PASS design
Purge tombstone minimal dans ligne canonique PASS design
Compacted non simulé ; rejet stable tant qu'aucun codec réel PASS design
Navigation index partiel (slot, signature) hors purged PASS design

5. Inventaire SQL minimal prévu

5.1 Tables

ksp_store_identity
ksp_raw_transactions
ksp_raw_transaction_observations
ksp_raw_transaction_archive_payloads

Statut pre.003 : matérialisé dans V001. Les quatre tables ci-dessus sont créées par la migration embedded V001__raw_transaction.sql; aucune capability/repository ne les consomme encore.

5.2 Indexes

PK ksp_raw_transactions(signature)
PK ksp_raw_transaction_observations(observation_key)
PK ksp_raw_transaction_archive_payloads(signature)
ix_ksp_raw_transactions_slot_signature(slot, signature)
    WHERE retention_state <> 'purged'

Tout index additionnel doit être justifié par une requête effectivement ajoutée à la release.

6. Mapping numérique sans narrowing

Valeur API Représentation SQL Cas limites obligatoires
slot: u64 NUMERIC(20,0) 0, i64::MAX, i64::MAX + 1, u64::MAX
format_version: u32 BIGINT 1, i32::MAX + 1, u32::MAX
RawTimestamp BIGINT 0, max documenté, max+1 DB hostile
source payload size BIGINT 0, 64 MiB, >64 MiB DB hostile
page limit bind signé de limit+1 seulement si représentable i64::MAX - 1, valeur supérieure rejetée

Critère : aucune branche ne doit utiliser as i64, as i32, clamp ou saturation pour faire tenir une valeur valide API.

7. Binding réseau

7.1 Bootstrap

Cas Résultat attendu
V001 appliquée pour la première fois identity créée avec le réseau runtime dans la transaction de bootstrap
réouverture même réseau succès idempotent
réouverture autre réseau erreur terminale sûre
V001 présente mais identity absente mismatch/corruption, jamais rebind silencieuse
identity malformée erreur terminale sûre
migration pending + auto_migrate disabled backend non prêt, aucune persistence métier

7.2 Pré-I/O capability

Pour tout input portant un RawNetworkId, un mismatch avec Store.network ou PostgresBackend.network doit être détecté avant acquisition d'un client du pool.

8. Idempotence canonique

État existant Input Mode Outcome attendu
absent canonique+observation valides Normal Inserted / Inserted
Full identique observation identique Normal AlreadyPresent / AlreadyPresent
Full identique observation nouvelle Normal AlreadyPresent / Inserted
Full divergent n'importe quelle observation Normal ERROR_CODE_RAW_CONFLICT, aucun write
Archived identique observation nouvelle Normal AlreadyPresent / Inserted
Purged compatible observation Normal SkippedPurged / NotRecorded
Purged divergent sur tombstone observation Normal ERROR_CODE_RAW_CONFLICT
Purged compatible observation ForceRehydrate Rehydrated / Inserted ou AlreadyPresent
Purged divergent observation ForceRehydrate ERROR_CODE_RAW_CONFLICT

L'égalité canonique compare les octets réels lorsqu'ils sont encore retenus. Le content hash seul n'est jamais une preuve suffisante dans Full ou Archived.

9. Atomicité canonique + observation

9.1 Cas obligatoires

Scénario Preuve attendue
nouvel insert, observation valide les deux commit
nouvel insert, observation divergente sur key déjà existante rollback canonique + observation
canonical conflict aucune nouvelle observation
cancellation avant commit aucun succès partiel visible
erreur SQL observation rollback canonique

9.2 FK

Le FK observation -> transaction est :

  • non nullable ;
  • sans ON DELETE SET NULL ;
  • impossible à contourner dans le repository métier ;
  • cohérent avec le fait que purge conserve la ligne canonique/tombstone.

10. Concurrence

Race Attendu
deux inserts identiques même signature un Inserted, l'autre AlreadyPresent; données identiques
deux inserts divergents même signature un gagnant, l'autre ERROR_CODE_RAW_CONFLICT
deux observations identiques même key un Inserted, l'autre AlreadyPresent
deux observations divergentes même key un gagnant, l'autre conflit
deux transitions vers même target un transitionne, l'autre AlreadyAtTarget
transitions avec expected incompatibles gagnant déterministe + ExpectedStateMismatch
purge vs acquisition sérialisation sur ligne canonique
purge vs ForceRehydrate aucun état moitié purgé/moitié full
deux ForceRehydrate idempotence ou conflit selon contenu

La preuve live doit utiliser de vraies tâches concurrentes, pas une simulation séquentielle renommée « concurrency ».

11. Observation write séparée

Cas Attendu
canonique Full présent, key absente Inserted
canonique Archived présent, key absente Inserted
key identique AlreadyPresent
key divergente ERROR_CODE_RAW_CONFLICT
canonique absent erreur sûre, aucune création implicite
canonique Purged NotRecorded
mauvais réseau rejet pré-I/O

L'absence du canonical requis est classée store.raw_reference_not_found. Ce code runtime ne modifie pas les invariants de construction de ksp-store-api.

12. Lecture

12.1 RawTransaction

État physique get_raw_transaction
Full cohérent Some(RawTransaction) depuis payload hot
Archived cohérent Some(RawTransaction) depuis archive relation
Purged None
row inconnue None
état/bytes/taille/numérique incohérents erreur sûre de donnée physique

12.2 Observation

Cas Résultat
key connue observation reconstruite avec network du backend bound
key inconnue None
bytes/provenance invalides en DB erreur sûre

13. Pagination

13.1 Ordre

Ascending  = (slot ASC,  signature ASC)
Descending = (slot DESC, signature DESC)

13.2 Dataset obligatoire

Le test doit contenir au minimum :

  • plusieurs slots ;
  • au moins trois signatures distinctes sur le même slot ;
  • suffisamment de rows pour trois pages ;
  • une row Purged exclue de la liste ;
  • bornes start/end présentes et absentes.

13.3 Cursor V1

Test Attendu
round-trip exact
taille != 109 rejet
magic modifié rejet
version inconnue rejet
digest modifié rejet
direction différente rejet
range différente rejet
network différent rejet
last slot hors range rejet
random bytes <=4096 rejet sans panic/echo
cursor >4096 au niveau API déjà rejeté par RawPageCursor

13.4 Pas de cap métier

Aucun test ne doit imposer 100, 500 ou 1000 comme limite Store. La seule erreur de taille côté backend doit correspondre à la représentation physique nécessaire au LIMIT + 1.

14. Rétention

14.1 États supportés physiquement en 0.3.3

Full
Archived
Purged

Compacted reste un état logique API connu, explicitement optionnel depuis le plan 0.3.1, mais non représenté mensongèrement par PostgreSQL 0.3.3. Le code store.postgres_retention_compaction_unsupported est matérialisé dès pre.003 dans ksp-store-postgres-lib et ksp-store-lib avec la même valeur KSP ; son usage opérationnel par les transitions sera branché en pre.007.

14.2 Matrice

Current Expected Target Attendu PostgreSQL 0.3.3
Full Full Archived Transitioned
Archived Full Archived AlreadyAtTarget
Archived Archived Purged Transitioned
Purged Archived Purged AlreadyAtTarget
Full Archived Purged input transition invalide au niveau API
Full Full Compacted store.postgres_retention_compaction_unsupported, pré-I/O
Compacted attendu Compacted Archived store.postgres_retention_compaction_unsupported, pré-I/O
Full Archived Archived ExpectedStateMismatch

14.3 Tombstone

Après purge, la reconstruction autorisée contient exactement :

reference
slot
format_id
format_version
content_hash

Le block time et les octets de payload ne restent pas dans la table hot ni dans la table archive.

15. ForceRehydrate

Cas Attendu
Purged + tombstone compatible restaure Full et payload, outcome Rehydrated
Purged + slot divergent conflict
Purged + format id/version divergent conflict
Purged + content hash divergent conflict
Full/Archived identique + Force idempotence normale, pas faux Rehydrated
race avec purge sérialisation ; état final cohérent

16. Erreurs et redaction

16.1 Canary hostile

Les tests devront injecter des valeurs sentinelles dans :

URI
server error text
SQL text simulé
signature
observation key
content hash
payload
provider/protocol/method
cursor bytes
row DB invalide

Aucune sentinelle ne doit apparaître dans Display, Debug ou message sûr retourné.

16.2 Classification

Classe Interface attendue
input/model invalide codes ksp-store-api acquis
canonical/observation divergent ERROR_CODE_RAW_CONFLICT
retention representation non supportée store.postgres_retention_compaction_unsupported
réseau incohérent code statique, pas de réseau hostile rendu
DB row invalide code statique de corruption/data invalid
query/write PostgreSQL code statique backend/runtime
pool/cancel/migration catégories runtime existantes ou extension statique justifiée

SQLSTATE et texte PostgreSQL ne font pas partie du contrat public.

17. Migration engine

17.1 Multi-version

Preuves acquises en pre.002 avant création réelle de V001 :

  • V000 reste byte-identique et conserve le checksum d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450 ;
  • le registre embedded privé est ordonné et commence à V000 ;
  • le moteur valide un historique comme préfixe exact du registre ;
  • un registre synthétique [V000, V001] prouve qu'un historique V000 seul retourne l'index pending V001 sans être classé mismatch ;
  • nom/checksum divergent, historique vide avec metadata existante ou trou de préfixe -> mismatch ;
  • version supérieure au registre connu -> schema newer, sans down migration ;
  • auto_migrate = false refuse un registre incomplet par migration_pending ;
  • les migrations pending sont appliquées dans l'ordre sous la transaction et l'advisory lock déjà acquis ;
  • chaque migration vérifie encore la forme de la metadata avant d'insérer sa ligne d'historique.

Preuves matérialisées en pre.003 avec la vraie V001 :

  • registre réel [V000, V001] et version courante dérivée 1 ;
  • historique V000 seul reconnu comme préfixe exact avec V001 pending ;
  • historique V000+V001 exact reconnu comme complet ;
  • checksum V001 figé à 6fe57ed0313d2ed295280dd6e49f6d86695d4e4effee2724a25e36db1ea17761 ;
  • binding réseau réel branché dans le hook StoreIdentity ;
  • inventaire physique exact : identity, canonical, observations, archive, index partiel ;
  • bornes SQL statiquement alignées sur u64, u32, RawTimestamp, payload 16 MiB et source payload 64 MiB.

L'application V000 -> V001, le rollback réel du hook, la réouverture même/autre réseau et la divergence de checksum sur PostgreSQL réel restent à prouver dans le gate live dédié pre.009; ils ne sont pas déclarés PASS dans cette tranche.

17.2 Binding réseau atomique

pre.002 prépare la frontière sans créer l'identité : RawNetworkId est transmis au moteur et chaque migration possède un hook privé exécuté sous la même transaction/advisory lock. Deux contextes sont distingués : AppliedNow pour une migration qui vient d'être exécutée et Existing pour une migration déjà présente dans l'historique lors d'une réouverture. V000 déclare explicitement le hook neutre.

pre.003 branche le hook V001 réel : en contexte AppliedNow, il insère la singleton puis relit/valide ksp_store_identity avant insertion de l'historique V001 ; en contexte Existing, il relit/valide strictement l'identité sans jamais la recréer. Une absence, un nombre de lignes inattendu, une forme invalide ou un réseau différent sont classés MigrationMismatch avec phase statique et sans rendre le réseau stocké. L'atomicité PostgreSQL réelle de ce chemin sera prouvée dans pre.009.

18. Boundaries

Les scans/tests doivent garantir :

ksp-store-lib -X-> tokio-postgres/deadpool-postgres/rustls
ksp-store-lib -X-> SQL literal
ksp-store-lib -X-> std::env / dotenv / libpq files
ksp-store-postgres-lib -X-> ksp-store-lib
ksp-store-postgres-lib -X-> direct Config ownership
ksp-store-api -X-> backend physical dependency

La façade ne publie aucun Client, Transaction, pool, TLS type, SQL row ou type backend.

19. Feature matrix

Build Attendu
ksp-store-lib default feature postgres active, six capacités dispatchables une fois implémentées
ksp-store-lib --no-default-features compile ; aucune dépendance backend tirée
config backend postgres sans feature erreur backend_not_compiled avant I/O
malformed postgres URI avec feature erreur safe pré-I/O comme 0.3.2

20. Audit historique — preuves de non-régression

Les tests/source scans devront empêcher le retour des patterns historiques rejetés :

has_raw_transaction_signature
BIGSERIAL id comme identity publique
slot BIGINT dans V001
canonical_json JSONB
processing_state
ON DELETE SET NULL
raw SQL error text dans Error
cap 500/1000 dans Store pagination

21. Planning de validation par tranche

pre.001

  • documents plan/validation ;
  • version 0.3.3-pre.1 ;
  • aucun SQL métier ;
  • gate workspace actuel.

pre.002

  • migration registry multi-version : PASS statique ;
  • V000/checksum conservés : PASS ;
  • validation préfixe/mismatch/newer : PASS unit design + canaris source ;
  • préparation hook binding réseau transactionnel : PASS ;
  • aucune V001 métier créée : PASS.

pre.003

  • V001 + tables/constraints/indexes : PASS statique ;
  • binding réseau hook AppliedNow/Existing : PASS statique ;
  • checksum/inventory/bounds tests : PASS statique ;
  • code postgres_retention_compaction_unsupported backend + façade : PASS ;
  • preuve PostgreSQL réelle V001 : différée à pre.009.

pre.004

  • row codecs et lectures ;
  • malformed DB matrix.

pre.005

  • atomic writes/idempotence/conflict ;
  • observation writes.

pre.006

  • list/cursor/order/ranges ;
  • hostile cursor matrix.

pre.007

  • archive/purge/tombstone/ForceRehydrate ;
  • Compacted unsupported stable.

pre.008

  • façade/feature dispatch ;
  • no physical leak ;
  • pre-I/O mismatch.

pre.009

  • PostgreSQL live opt-in complet.

pre.010

  • hardening/completeness.

pre.011

  • gate technique final.

pre.012

  • réconciliation documentaire.

pre.013

  • publication prep.

rel.001

  • publication stable.

22. Gate courant pre.002

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.3
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-store-api
cargo test -p ksp-store-lib
cargo test -p ksp-store-postgres-lib
cargo test -p ksp-config-lib
cargo check -p ksp-store-lib --no-default-features

23. Critère de clôture de release

0.3.3 ne pourra être déclarée stable que si :

  • les six capacités sont réellement implémentées sur PostgresBackend et dispatchées par Store ;
  • aucune valeur valide API n'est narrowée ;
  • l'idempotence distingue strictement identité identique et contenu divergent ;
  • canonical+observation est atomique ;
  • pagination est déterministe et cursorisée ;
  • réseau physique incorrect est refusé ;
  • rétention supportée est honnête et atomique ;
  • Compacted n'est pas prétendu sans représentation réelle ;
  • tombstone et ForceRehydrate respectent les contrats acquis ;
  • les erreurs ne fuient aucun secret/SQL/server text ;
  • le live PostgreSQL opt-in couvre concurrence et rollback ;
  • tous les gates techniques/doc sont propres ;
  • aucun scope RawAccountState/worker/app/N2 n'a été ouvert.