Files
khadhroony-solana-project/docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md

52 KiB
Raw Blame History

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. pre.003 a été commité avant son gate opérateur ; pre.003-fix.001 corrige donc sa matérialisation physique par-dessus ce commit. Son premier gate opérateur a ensuite révélé un défaut de binding ToSql dans lintrospection catalogue et un faux positif ownership dû à des constantes internes KSP_*; pre.003-fix.002 corrige uniquement ces deux défauts sans modifier le contrat physique ni les checksums de migration. Son gate opérateur compile désormais le backend mais révèle trois reliquats locaux : un binding inutilisé, cinq usages de ? interdits par la policy Clippy KSP et un include_str! du test live resté sur lancien chemin V000 ; pre.003-fix.003 corrige uniquement ces reliquats sans toucher aux ressources SQL ni aux checksums. 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 PASS pre.008 PASS pre.008 unit + integration + live
RawTransactionWrite PASS pre.008 PASS pre.008 unit + concurrency live
RawTransactionObservationRead PASS pre.008 PASS pre.008 unit + live
RawTransactionObservationWrite PASS pre.008 PASS pre.008 unit + concurrency live
RawTransactionRetentionRead PASS pre.008 PASS pre.008 unit + live
RawTransactionRetentionWrite PASS pre.008 PASS pre.008 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 après pre.003-fix.001 : matérialisé dans V001. Les quatre tables sont des ressources embedded distinctes sous migrations/v001_raw_transaction/tables/; contraintes et index sont séparés dans leurs propres sous-répertoires. V001 reste une migration logique unique et 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 + schema_autoupdate=false 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.

Le commit pre.003 a matérialisé la vraie V001 et son binding réseau, mais son fichier SQL monolithique et le seul contrôle de l'historique ne suffisaient pas à prouver la compatibilité structurelle de la base. Son checksum V001 historique de prerelease était 6fe57ed0313d2ed295280dd6e49f6d86695d4e4effee2724a25e36db1ea17761.

Preuves statiques ajoutées par pre.003-fix.001 :

  • V000 déplacée byte-identique, checksum toujours d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450 ;
  • V001 logique unique composée de 40 ressources ordonnées : 4 tables, 35 contraintes et 1 index ;
  • checksum V001 multi-ressources 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51 ;
  • anciens fichiers monolithiques absents après application du delta ;
  • CREATE ... IF NOT EXISTS/guards servent uniquement à la création additive, jamais à déclarer un objet compatible ;
  • inspection catalogue indépendante de l'historique avec états Compatible, Missing, Incompatible ;
  • contraintes attendues comparées exactement à une définition canonique issue de la ressource SQL correspondante ;
  • colonne externe nullable sans default/identity/generated acceptée comme extension non bloquante ;
  • index externe non unique accepté ;
  • mauvais type/nullabilité sur colonne obligatoire, extra colonne write-blocking, contrainte externe non équivalente, unique index autonome, trigger actif, rule ou RLS bloquent Ready ;
  • ressource obligatoire manquante réparable seulement lorsque la politique le permet et que la réparation est additive/sûre ;
  • identité V001 manquante sur un historique déjà appliqué reste terminale et n'est jamais auto-recréée ;
  • std.store V2 sépare schema_autocreate et schema_autoupdate, avec lecture V1 conservée et mapping de auto_migrate vers les deux valeurs.

L'application V000 -> V001, les réparations réelles, le rollback du hook, la réouverture même/autre réseau et la matrice de drift sur PostgreSQL réel restent à prouver dans le gate live dédié pre.009; elles ne sont pas déclarées PASS par le correctif statique. Une base ayant déjà enregistré l'ancien checksum V001 de pre.003 doit être réinitialisée ou réconciliée manuellement ; le moteur ne réécrit pas son historique silencieusement.

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 : matérialisé puis corrigé par pre.003-fix.001 ;
  • binding réseau hook AppliedNow/Existing : PASS statique ;
  • code postgres_retention_compaction_unsupported backend + façade : PASS ;
  • gate opérateur pre.003 : NON FOURNI avant le correctif.

pre.003-fix.001

  • arborescence versionnée et 40 ressources V001 : PASS statique ;
  • V000 byte-identique/checksum historique : PASS statique ;
  • checksum/inventory/order V001 multi-ressources : PASS statique ;
  • contrat catalogue Compatible/Missing/Incompatible : PASS statique ;
  • politiques schema_autocreate / schema_autoupdate + compatibilité Config V1 : PASS statique ;
  • extensions externes non bloquantes tolérées, extensions write-blocking refusées : PASS statique ;
  • preuve PostgreSQL réelle V001/drift/réparation : différée à pre.009 ;
  • gate Cargo opérateur : FAIL sur schema.rs (&str/ToSql) puis sur les canaris ownership Config (KSP_* interne interprété comme variable runtime).

pre.003-fix.002

  • binding des paramètres catalogue &str vers ToSql corrigé avec &&str : PASS statique ;
  • constantes de contrat renommées sans préfixe KSP_ réservé au namespace denvironnement Config : PASS statique ;
  • aucune ressource SQL, aucun ordre de migration et aucun checksum V000/V001 modifié ;
  • gate opérateur : FAIL Clippy (question_mark_used + warning) et ancien include_str! V000 du test live.

pre.003-fix.003

  • warning unused variable, opérateurs ? et canari test Clippy corrigés : PASS ;
  • postgres_foundation_live relocalisé vers V000 versionnée : PASS ;
  • README/USAGE backend réconciliés avec l'arborescence split : PASS ;
  • gate opérateur complet du 2026-08-30 : PASS (check, Clippy, Store/API/PostgreSQL/Config, no-default-features).

pre.004

  • quatre lectures RAW backend-specific sans fuite de row/SQL : PASS ;
  • conversion NUMERIC(20,0) -> u64 jusqu'à u64::MAX et conversions entières/timestamps fallibles : PASS ;
  • Full/Archived/Purged, observation complète, rétention/tombstone : PASS ;
  • mauvais réseau avant pool I/O : PASS ;
  • malformed DB -> DataInvalid, SELECT -> ReadFailed, aucune valeur hostile retenue : PASS ;
  • SQL strictement read-only dans cette tranche : PASS ;
  • gate opérateur complet du 2026-08-30 : PASS (check, Clippy, Store/API/PostgreSQL/Config, no-default-features ; 25 tests unit backend).

pre.005

  • acquisition transaction + observation atomique sous transaction SQL : PASS statique/design ;
  • insert unique sans has_*, puis verrouillage FOR UPDATE et comparaison réelle : PASS statique/unit design ;
  • même contenu -> AlreadyPresent, divergence -> Conflict : PASS unit design ;
  • tombstone compatible Normal -> SkippedPurged/NotRecorded : PASS statique/design ;
  • tombstone compatible ForceRehydrate -> Rehydrated + observation atomique : PASS statique/design ;
  • observation write séparée, key identique/divergente, absent/purged : PASS statique/unit design ;
  • Conflict / ReferenceNotFound / WriteFailed sans texte serveur : PASS statique ;
  • preuve PostgreSQL concurrente/rollback réelle : différée à pre.009 ;
  • gate opérateur complet du 2026-08-30 : PASS (check, Clippy, Store/API/PostgreSQL/Config, no-default-features ; 30 tests unit backend).

pre.006

  • list_raw_transactions backend-specific et mauvais réseau pré-I/O : PASS statique/unit design ;
  • ordre total ASC/DESC (slot, signature) et keyset stricte sans OFFSET : PASS statique ;
  • bornes inclusives et exclusion Purged : PASS statique ;
  • cursor V1 fixe 109 octets, magic/version/last key/digest : PASS unit design ;
  • binding digest network/direction/range + replay hostile rejeté : PASS unit design ;
  • taille/magic/version/digest/random bytes hostiles : PASS unit design ;
  • last_slot hors range rejeté : PASS unit design ;
  • LIMIT requested + 1, limite i64::MAX - 1, aucun cap worker : PASS unit/statique ;
  • index V001 (slot, signature) partiel réutilisé, migration inchangée : PASS statique ;
  • snapshot inter-pages explicitement non garanti : PASS doc ;
  • premier gate opérateur : FAIL local sur re-export cursor inutilisé + placeholder manquant du canari hardening ;
  • pre.006-fix.001 corrige uniquement ces deux défauts ; gate opérateur complet du 2026-08-30 : PASS (check, Clippy, Store/API/PostgreSQL/Config, no-default-features ; 34 tests unit backend).

pre.007

  • méthode backend-specific de transition : PASS statique ;
  • network + Compacted rejetés pré-I/O : PASS unit design ;
  • Full -> Archived et Archived -> Purged sous FOR UPDATE : PASS statique/unit decision ;
  • AlreadyAtTarget / ExpectedStateMismatch / Applied : PASS unit decision ;
  • archive payload/hot payload/block time validés selon l'état avant mutation/no-op : PASS statique ;
  • unknown reference -> ReferenceNotFound : PASS statique ;
  • RetentionCompactionUnsupported stable, aucune représentation compacted SQL : PASS statique/unit ;
  • preuve des races et atomicité PostgreSQL réelle : différée à pre.009 ;
  • premier gate opérateur : FAIL local sur un canari pre.005 devenu obsolète après ouverture légitime du DELETE de purge en pre.007 ;
  • pre.007-fix.001 retire uniquement cette interdiction historique globale et conserve le garde-fou jusqu'à ouverture de pre.008 ; gate opérateur complet PASS le 2026-08-30.

pre.008

  • six implémentations RawTransaction* sur PostgresBackend : PASS compile/test ;
  • six dispatches correspondants sur Store : PASS compile/test ;
  • validation réseau façade pré-dispatch : PASS unit/static ;
  • RawTransactionObservationRead reste scoped par l'instance mono-réseau car l'input ne porte aucun réseau ;
  • mapping Conflict -> store_api.raw_conflict, QueryInvalid -> store_api.raw_query_invalid : PASS statique/unit ;
  • codes wrong_network, raw_reference_not_found, read/write/data/page-limit PostgreSQL stabilisés : PASS public canary ;
  • aucune fuite PostgreSQL/SQL/env/reverse edge et aucun RawAccount* : PASS boundary canaries ;
  • --no-default-features : PASS ;
  • V000/V001 inchangées ;
  • premier gate opérateur : fonctionnellement PASS mais deux warnings Clippy extra_unused_type_parameters dans les helpers de preuve de traits ;
  • pre.008-fix.001 matérialise T via PhantomData<T> dans ces deux helpers sans modifier les bounds, la production ni les migrations ; gate opérateur complet PASS le 2026-08-30.

pre.009

  • test postgres_raw_transaction_live dédié et #[ignore] : MATÉRIALISÉ ;
  • base dédiée obligatoire, refus de toute table KSP préexistante, URI lue sur stdin sans echo : PASS statique ;
  • bootstrap V000/V001 + réouverture + wrong-network : COUVERT par le test, exécution réelle À FOURNIR ;
  • réparation additive index avec schema_autoupdate off/on : COUVERTE par le test, exécution réelle À FOURNIR ;
  • canonical+observation atomique + exact reads : COUVERT ;
  • identical/divergent concurrent inserts : COUVERT en tâches tokio::spawn ;
  • observation idempotence/divergence + rollback canonical sur conflit observation : COUVERT ;
  • pagination multi-page/ties ASC-DESC + replay cursor autre direction/range : COUVERT ;
  • archive/purge/tombstone/normal-skip/ForceRehydrate compatible-divergent/Compacted : COUVERT ;
  • races archive et purge : COUVERT en tâches concurrentes ;
  • cancellation : verrou observation PostgreSQL + acquisition bloquée + abort() + canonical absent après rollback : COUVERT ;
  • réouverture finale : COUVERTE ;
  • premier gate Cargo opérateur : FAIL local de compilation dans le scénario cancellation, car un Result<Transaction<'_>> intermédiaire prolongeait l'emprunt mutable de admin jusqu'au probe final ;
  • pre.009-fix.001 supprime uniquement ce binding intermédiaire et matche directement admin.transaction().await, sans modifier la preuve, le SQL, la production ni les migrations ;
  • gate opérateur pre.009-fix.001 du 2026-08-30 : cargo check --workspace, tests API/façade/backend/Config et --no-default-features passent, mais Clippy bloque le test live sur trois closures sans return explicite et remonte deux guards redondants ;
  • live réel pre.009-fix.001 avec URI dédiée valide : PostgreSQL 17 est joint, puis l'ouverture backend échoue encore sous l'étiquette trop générique backend_open ; aucune conclusion sur le schéma n'est tirée sans phase sûre plus précise ;
  • pre.009-fix.002 corrige uniquement les cinq diagnostics Clippy du test et propage PostgresBackendError::phase() vers LiveFailure lors de open_backend, sans rendre le texte PostgreSQL, l'URI, SQLSTATE ou bind ;
  • gate Cargo standard de pre.009-fix.002 du 2026-08-30 : PASS complet, audits/check/Clippy/tests/no-default-features propres ;
  • live PostgreSQL réel pre.009-fix.002 : PostgreSQL 17 joint puis FAIL à schema_resource_post_apply, ce qui localise le défaut dans la relecture d'une ressource V001 juste après son application ;
  • pre.009-fix.003 conserve la redaction mais remplace, uniquement pour ce cas post-apply, la phase agrégée par resource.id, identifiant embarqué statique et non sensible ;
  • gate Cargo standard de pre.009-fix.003 du 2026-08-30 : PASS complet ;
  • live PostgreSQL réel pre.009-fix.003 : PostgreSQL 17 joint puis FAIL précisément sur constraints/006_ck_ksp_raw_transactions_slot.sql ;
  • diagnostic : le CHECK est appliqué, mais la forme catalogue PostgreSQL peut rendre la borne NUMERIC hors bigint comme littéral quoté '18446744073709551615'::numeric, tandis que l'ancien normaliseur conservait les quotes ;
  • pre.009-fix.004 corrige l'équivalence catalogue des littéraux NUMERIC quotés et ajoute un canari qui préserve les quotes des littéraux texte ; aucune ressource SQL/migration n'est modifiée ;
  • gate Cargo standard pre.009-fix.004 du 2026-08-30 : PASS complet ;
  • live PostgreSQL réel pre.009-fix.004 : le CHECK slot passe désormais et l'échec se déplace précisément sur constraints/007_ck_ksp_raw_transactions_block_time.sql ;
  • diagnostic : block_time_unix_millis est BIGINT, et la reconstruction catalogue peut typer une grande constante entière sous forme de littéral quoté suivi d'un cast intégral ; la normalisation ciblée de fix.004 ne couvrait encore que ::numeric ;
  • pre.009-fix.005 généralise uniquement cette canonicalisation aux casts numériques/intégraux PostgreSQL (numeric, bigint, integer, smallint, int8, int4, int2) sans retirer les quotes des littéraux textuels.

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.009

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.

pre.003-fix.003

  • [PASS] correction du binding local inutilisé dans linventaire des indexes uniques ;
  • [PASS] extraction de définition de contrainte sans opérateur ?, conformément à clippy::question_mark_used = deny ;
  • [PASS] canari unitaire sans assertion constante ;
  • [PASS] test live V000 relocalisé vers migrations/v000_bootstrap/tables/001_ksp_store_schema_migrations.sql ;
  • [PASS] aucune ressource SQL V000/V001 modifiée ; checksums inchangés ;
  • [PASS] gate opérateur complet de fix.003 fourni le 2026-08-30.

pre.004 — état de la tranche

  • [PASS] module privé raw_transaction avec SELECT uniquement ;
  • [PASS] get_raw_transaction Full/Archived/Purged ;
  • [PASS] get_raw_transaction_observation et provenance complète ;
  • [PASS] lectures rétention/tombstone ;
  • [PASS] conversions fallibles NUMERIC(20,0)/BIGINT/BYTEA/TEXT sans narrowing ;
  • [PASS] wrong-network gardé avant pool I/O ;
  • [PASS] ReadFailed / DataInvalid / WrongNetwork sans texte externe ;
  • [PASS] tests déterministes de row mapping et hostile data ajoutés ;
  • [PASS] gate Cargo opérateur complet de pre.004 fourni le 2026-08-30.

pre.005 — état de la tranche

  • [PASS] écritures backend-specific canonique + observation ajoutées sans implémenter encore les traits incomplets ;
  • [PASS] validation réseau et cohérence transaction/observation avant pool.get() ;
  • [PASS] idempotence par insert unique + comparaison réelle sous FOR UPDATE, sans has_* ;
  • [PASS] payload comparé byte-for-byte lorsque disponible ;
  • [PASS] Purged normal skip et ForceRehydrate atomique selon tombstone ;
  • [PASS] observation write séparée : Inserted / AlreadyPresent / NotRecorded / conflit ;
  • [PASS] référence canonique absente classée ReferenceNotFound ;
  • [PASS] erreurs physiques d'écriture classées WriteFailed sans conserver le texte PostgreSQL ;
  • [PASS] aucune migration SQL modifiée et aucun scope pagination/rétention mutante ouvert ;
  • [PASS] gate Cargo opérateur complet de pre.005 fourni le 2026-08-30.

pre.006 — état de la tranche

  • [PASS] bridge list_raw_transactions ajouté sans type PostgreSQL public ;
  • [PASS] keyset stricte ASC/DESC sur (slot, signature), sans OFFSET ;
  • [PASS] bornes de slots inclusives et tombstones Purged exclus ;
  • [PASS] cursor V1 fixe 109 octets et digest lié à la query ;
  • [PASS] replay network/direction/range et cursor hostile classés QueryInvalid ;
  • [PASS] limite physique requested <= i64::MAX - 1, au-delà PageLimitUnsupported sans clamp ;
  • [PASS] aucune migration SQL modifiée, aucun scope rétention mutante/façade ouvert ;
  • [PASS] premier gate a isolé deux défauts purement locaux, corrigés en pre.006-fix.001.

pre.006-fix.001 — correction du gate

  • [PASS] re-export crate-private RawTransactionDecodedCursor inutilisé supprimé sans modifier le codec cursor ;
  • [PASS] canari hardening_completeness corrigé pour concaténer les huit sources backend inspectées ;
  • [PASS] aucune logique SQL, pagination, migration ou checksum V000/V001 modifiée ;
  • [PASS] gate Cargo opérateur complet fourni le 2026-08-30.

pre.007 — état de la tranche

  • [PASS] bridge backend-specific transition_raw_transaction_retention ajouté ;
  • [PASS] validation réseau et Compacted avant pool I/O ;
  • [PASS] compare-and-transition sérialisé par verrou canonical FOR UPDATE ;
  • [PASS] Full -> Archived copie le payload exact vers archive puis retire le payload hot atomiquement ;
  • [PASS] Archived -> Purged supprime l'archive, efface block time et conserve le tombstone minimal ;
  • [PASS] AlreadyAtTarget, ExpectedStateMismatch, Applied décidés depuis l'état verrouillé ;
  • [PASS] RetentionCompactionUnsupported utilise le code stable déjà acquis ;
  • [PASS] aucune migration SQL modifiée, aucun trait Store complet ni dispatch façade ouvert ;
  • [FAIL local] premier gate Cargo opérateur : le canari historique pre_005_raw_write_sql_is_atomic_idempotent_and_keeps_later_scope_closed interdisait encore globalement DELETE FROM, désormais légitime pour Archived -> Purged.

pre.007-fix.001 — correction du gate

  • [PASS statique] le canari pre.005 conserve ses assertions d'atomicité/idempotence et n'interdit plus le DELETE introduit explicitement par pre.007 ;
  • [PASS statique] les implémentations directes RawTransactionWrite / RawTransactionObservationWrite restent interdites dans le backend à ce stade ;
  • [PASS statique] le canari pre.007 continue d'exiger DELETE_ARCHIVE_PAYLOAD_SQL et DELETE FROM ksp_raw_transaction_archive_payloads ;
  • [PASS statique] aucune logique runtime, migration ou checksum V000/V001 modifié ;
  • [PASS] gate Cargo opérateur complet de pre.007-fix.001 fourni le 2026-08-30.

pre.009-fix.004 — normalisation PostgreSQL 17 du CHECK slot

  • [PASS opérateur] gate standard pre.009-fix.003 intégralement propre le 2026-08-30 ;
  • [DIAGNOSTIC LIVE] PostgreSQL 17 identifie exactement constraints/006_ck_ksp_raw_transactions_slot.sql comme ressource incompatible immédiatement après application ;
  • [FIX] l'introspection normalise les littéraux numériques quotés suivis de ::numeric, forme reconstruite pour la borne NUMERIC hors plage bigint ;
  • [PASS] le canari couvre '18446744073709551615'::numeric et vérifie que les littéraux texte comme 'full'::text conservent leurs quotes ;
  • [PASS] aucun fichier SQL V000/V001, ordre de ressource ou checksum de migration n'est modifié ;
  • [PASS opérateur] gate Cargo complet pre.009-fix.004 fourni le 2026-08-30 ;
  • [DIAGNOSTIC LIVE] le CHECK slot est désormais accepté ; PostgreSQL 17 poursuit V001 puis s'arrête sur constraints/007_ck_ksp_raw_transactions_block_time.sql.

pre.009-fix.005 — canonicalisation des littéraux numériques/intégraux typés

  • [DIAGNOSTIC] block_time_unix_millis est BIGINT et sa borne haute 253402300799999 est une constante entière large ; le catalogue reconstruit les expressions, il ne restitue pas nécessairement le texte SQL source ;
  • [FIX statique] le normaliseur retire quotes + cast uniquement pour un littéral ASCII intégral ([+-]?[0-9]+) suivi de ::numeric, ::bigint, ::integer, ::smallint, ::int8, ::int4 ou ::int2 ;
  • [PASS statique] le canari couvre explicitement le CHECK block_time sous forme '253402300799999'::bigint ainsi qu'un alias ::int8 ;
  • [PASS statique] les quotes des littéraux texte restent préservées et aucune comparaison métier n'est relâchée ;
  • [PASS statique] aucune ressource SQL V000/V001 ni checksum de migration n'est modifié ;
  • [À FAIRE] gate Cargo opérateur complet puis live PostgreSQL postgres_raw_transaction_live.

pre.009-fix.006 — restauration du tail schema.rs et classification du drift avec auto-update désactivé

  • [PASS opérateur] gate standard pre.009-fix.005 propre après restauration des helpers privés supprimés accidentellement par l'overlay : schema_incompatible, schema_query_error et le module de tests schema ;
  • [DIAGNOSTIC LIVE] PostgreSQL 17 applique désormais V001 puis le scénario de preuve atteint schema_autoupdate_disabled_classification après suppression volontaire de l'index géré ;
  • [FIX] une ressource manquante appartenant à une migration déjà enregistrée est classée MigrationMismatch lorsque schema_autoupdate=false, car le schéma physique diverge de l'historique déclaré ;
  • [PASS statique] un helper privé centralise cette classification et un test unitaire vérifie le couple exact MigrationMismatch / schema_autoupdate_disabled ;
  • [PASS statique] migration_pending, schema_autocreate_disabled et les autres refus purement policy restent MigrationFailed ;
  • [PASS statique] aucune ressource SQL V000/V001, ordre de ressource ou checksum de migration n'est modifié ;
  • [À FAIRE] gate Cargo opérateur puis live PostgreSQL postgres_raw_transaction_live.