# Validation `0.3.3` — Store/PostgreSQL RawTransaction vertical slice ## 1. Objet Cette validation accompagne : ```text 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 l’introspection 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 l’ancien 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` ```text 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 ```text 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 ```text 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 ```text 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` ```text 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 : ```text 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 : ```text 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 : ```text 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 : ```text 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 d’environnement 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` 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>` 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.012` ```bash 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 l’inventaire 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`. ### `pre.009-fix.006` — clôture opérateur et live PostgreSQL 17 - [PASS] gate standard complet propre le 2026-08-30 ; - [PASS] `ksp-store-postgres-lib` : 40 tests unitaires, 9 boundary, 5 hardening, 9 public API ; - [PASS] preuve live `postgres_raw_transaction_live` sur PostgreSQL 17 : 1 test passé ; - [PASS] bootstrap V000/V001, drift/repair, écritures concurrentes, pagination, rétention, cancellation et réouverture finale exercés ; - [PASS] aucune migration SQL ni checksum V000/V001 modifié ; - [PASS] `pre.009` est fermée et `pre.010` peut ouvrir le hardening final. ### `pre.010` — hardening/completeness - [PASS statique] inventaire exact d’une implémentation de chacun des six traits `RawTransaction` côté `PostgresBackend` et côté `Store` ; - [PASS statique] absence d’implémentation `RawAccountState` et de ressource `ksp_raw_account*` ; - [PASS statique] canari SQL conserve keyset ASC/DESC, `LIMIT`, `FOR UPDATE`, les deux formes ciblées `ON CONFLICT (...) DO NOTHING` et archive séparée, sans `OFFSET`, `SELECT *`, `ON CONFLICT DO UPDATE` ni policy worker ; - [PASS statique] les 18 variantes actuelles de `PostgresBackendErrorKind` sont couvertes par le mapping capability backend et par le mapping façade ; - [PASS statique] aucun fichier de production ou migration n’est modifié ; checksums V000/V001 inchangés ; - [FAIL local] premier gate opérateur : le canari SQL cherchait littéralement `ON CONFLICT DO NOTHING`, sous-chaîne absente des formes réelles `ON CONFLICT (signature) DO NOTHING` et `ON CONFLICT (observation_key) DO NOTHING`. ### `pre.010-fix.001` — correction du canari `ON CONFLICT` - [PASS statique] le canari exige désormais explicitement `ON CONFLICT (signature) DO NOTHING` et `ON CONFLICT (observation_key) DO NOTHING` ; - [PASS statique] l’idempotence canonique et observation est donc vérifiée contre les deux statements réellement possédés par `raw_transaction.rs` ; - [PASS statique] aucune logique runtime, SQL de production, migration ou checksum V000/V001 n’est modifié ; - [À FAIRE] gate Cargo opérateur complet de `pre.010-fix.001`. ### `pre.010-fix.001` — clôture opérateur du hardening - [PASS] gate standard complet propre le 2026-08-30 ; - [PASS] audits Rust/Markdown, workspace check et Clippy all-targets ; - [PASS] `ksp-store-api` : 15 unitaires, 2 boundary, 1 external backend, 7 public API, 5 release completeness, 4 security hardening ; - [PASS] `ksp-store-lib` : 10 unitaires, 3 boundary, 1 feature mismatch, 5 hardening, 5 public API ; - [PASS] `ksp-store-postgres-lib` : 41 unitaires, 9 boundary, 7 hardening, 9 public API ; lives normalement ignored ; - [PASS] `ksp-config-lib` : 128 unitaires, 7 ownership, 17 public API ; - [PASS] `cargo check -p ksp-store-lib --no-default-features` ; - [PASS] le canari SQL exact exige les deux formes `ON CONFLICT (signature) DO NOTHING` et `ON CONFLICT (observation_key) DO NOTHING` ; - [PASS] aucune production, migration ou checksum V000/V001 modifié ; - [PASS] `pre.010` est fermée et `pre.011` peut ouvrir le gate technique final. ### `pre.011` — gate technique final - [PASS] `cargo fmt --all`, audits Rust/Markdown, `cargo check --workspace` et Clippy all-targets le 2026-08-30 ; - [PASS] tests ciblés `ksp-store-api`, `ksp-store-lib`, `ksp-store-postgres-lib` et `ksp-config-lib` ; - [PASS] `ksp-store-lib` testé et compilé avec `--no-default-features` ; - [PASS] `cargo test --workspace` sur l'ensemble des crates ; - [PASS] graphes Cargo normal/features/duplicates exécutés pour la façade et le backend ; - [PASS] replay `postgres_raw_transaction_live` sur PostgreSQL major 17 : `1 passed`, avec bootstrap/drift-repair, atomicité/concurrence, rollback, pagination, rétention/races, ForceRehydrate et réouverture ; - [N/A] builds Tauri : aucune resource applicative ni packaging desktop n'est modifié par `0.3.3` ; - [PASS] V000/V001 et leurs checksums restent byte-identiques à la preuve live `pre.009-fix.006` ; - [PASS] `pre.011` ferme la preuve technique et autorise la réconciliation documentaire `pre.012`. ### `pre.012` — réconciliation documentaire finale - [PASS] gate documentaire/opérateur complet propre le 2026-08-30 ; - [PASS] audits Rust/Markdown, workspace check, Clippy all-targets et tests ciblés Store/Config ; - [PASS] `cargo check -p ksp-store-lib --no-default-features` ; - [PASS] plan `024`, validation `020`, indexes durables, `CHANGELOG.md` et `ROADMAP.md` réconciliés ; - [INVARIANT] aucun code, test, Config runtime, architecture, règle, SQL ou migration n'est rouvert. ### `pre.012-fix.001` — conformité des rôles documentaires - [CORRECTION] les `USAGE.md` façade/backend ne contiennent plus de chronologie `pre.*`, de preuve de gate ou de renvoi à la validation comme contenu d'usage ; - [CORRECTION] les `USAGE.md` sont restructurés en guide pratique avec exemples pour lifecycle, lecture, pagination, écriture, observation et rétention ; - [CORRECTION] les README restent descriptifs et ne portent plus l'historique des prereleases ni le récit de validation live ; - [CONFORMITÉ] `KSP-REL-013` et `docs/rules/FILE_CONTRACTS.md` étaient déjà normatifs ; aucune règle supplémentaire n'est nécessaire ; - [INVARIANT] aucun code, test, Config runtime, architecture, SQL ou migration n'est modifié ; - [À FAIRE] gate documentaire/opérateur du correctif.