# Delta `0.3.4-pre.009` — preuve PostgreSQL live `RawAccountState` ## 1. Base et gate d'entrée Base opérateur obligatoire : ```text 0.3.4-pre.008-fix.001 ``` Le gate opérateur fourni le 2026-08-30 est entièrement propre : audits Rust/Markdown, `cargo check --workspace`, Clippy all-targets, Store API, Store façade, backend PostgreSQL, Config et `ksp-store-lib --no-default-features` passent. L'inventaire RAW 10/10 de `pre.008` est donc acquis. ## 2. Version ```text workspace.package.version = 0.3.4-pre.9 ``` ## 3. Nouveau test PostgreSQL réel account La tranche ajoute : ```text crates/ksp-store-postgres-lib/tests/postgres_raw_account_live.rs ``` Le test est `#[ignore]`, lit une URI PostgreSQL dédiée uniquement sur `stdin`, ne l'affiche jamais et refuse de démarrer lorsqu'une table KSP V000/V001/V002 existe déjà. Il ne nettoie que le schéma qu'il a prouvé absent avant son propre bootstrap. PostgreSQL < 15 est refusé comme pour les preuves live existantes. ## 4. Bootstrap, réseau, migration V002 et schema update La preuve couvre : - bootstrap V000 + V001 + V002 sur base vide ; - health Ready avec migration 2 ; - refus d'une réouverture sous un autre `RawNetworkId` ; - réouverture idempotente ; - suppression contrôlée de `ix_ksp_raw_account_states_slot_pubkey_state_hash` ; - `schema_autoupdate=false` qui bloque le drift ; - `schema_autoupdate=true` qui recrée et revalide l'index account manquant. Aucune ressource de migration n'est modifiée et aucun historique n'est réécrit. ## 5. Domaine account et round-trip Le live matérialise les extrêmes figés par `pre.001` : ```text slot = u64::MAX lamports = u64::MAX rent_epoch = u64::MAX write_version = u64::MAX data vide = admise data 16 MiB exact = admise et relue complète ``` La lecture réouverte doit restituer exactement la référence, le contenu commun et les metadata optionnelles sans narrowing. ## 6. Atomicité, idempotence, conflits et observations La preuve couvre : - acquisition state + observation `Inserted/Inserted` ; - replay exact `AlreadyPresent/AlreadyPresent` ; - même référence complète avec contenu divergent -> `Conflict` ; - même `(pubkey, slot)` avec deux `state_hash` distincts -> deux states durables ; - collision d'`observation_key` pendant une nouvelle acquisition -> `Conflict` et rollback du state nouvellement tenté ; - observation supplémentaire -> `Inserted`, puis replay exact -> `AlreadyPresent` ; - même observation key divergente -> `Conflict` ; - référence state absente -> `ReferenceNotFound` ; - round-trip exact de la provenance commune et des metadata Yellowstone `is_startup`, `transaction_signature`, `write_version`. ## 7. Pagination et cursor `KSPA` Le test matérialise cinq states sur la plage `200..=202` et prouve : ```text ASC (slot, pubkey, state_hash) DESC (slot, pubkey, state_hash) intégralement inversé page size = 2 filtre pubkey exact ``` Il rejoue ensuite le cursor sous direction différente, corrompt son digest, puis fournit un token de famille transaction `KSPT`. Les trois cas doivent être `QueryInvalid`. Aucun `OFFSET`, plafond fonctionnel de page, batch-size ou policy worker n'est introduit. ## 8. Concurrence réelle Deux acquisitions identiques sont lancées en vraies tâches concurrentes : le résultat attendu est exactement un `Inserted` et un `AlreadyPresent`. Deux acquisitions divergentes partageant la même référence `(pubkey, slot, state_hash)` sont ensuite lancées en concurrence : exactement une gagne et l'autre doit produire `Conflict`. ## 9. Cancellation réelle Le test : 1. crée une observation account durable ; 2. verrouille cette `observation_key` via une transaction PostgreSQL administrateur `FOR UPDATE` ; 3. démarre une nouvelle acquisition qui insère son state dans une transaction non committée puis bloque sur la collision observation ; 4. vérifie que l'opération reste bloquée au-delà du délai canari ; 5. l'annule via `JoinHandle::abort()` ; 6. libère le verrou administrateur ; 7. vérifie physiquement que le state de l'acquisition annulée n'est pas durable. Cette preuve exerce le rollback par cancellation réelle figé en `pre.006`. ## 10. Coexistence `RawTransaction` Dans le même schéma V002, le live persiste une acquisition account et une acquisition transaction utilisant volontairement la même `RawObservationKey` dans leurs tables familiales distinctes. Les deux familles doivent rester lisibles indépendamment, et la transaction est aussi vérifiée physiquement avant le reopen final. Le test historique `postgres_raw_transaction_live.rs` est réconcilié uniquement sur son inventaire d'isolation : son probe et son cleanup prennent désormais aussi en compte : ```text ksp_raw_account_states ksp_raw_account_observations ``` Aucun scénario métier RawTransaction n'est modifié. ## 11. Isolation et cleanup Les deux lives considèrent désormais l'inventaire complet de tables Store V002 : ```text ksp_store_schema_migrations ksp_store_identity ksp_raw_transactions ksp_raw_transaction_observations ksp_raw_transaction_archive_payloads ksp_raw_account_states ksp_raw_account_observations ``` Ils refusent un schéma préexistant et ne suppriment que le schéma qu'ils ont eux-mêmes bootstrapé après preuve d'absence initiale. ## 12. Migrations Aucune ressource V000/V001/V002 n'est modifiée. Checksums attendus : ```text V000 d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450 V001 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51 V002 ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e ``` ## 13. Fichiers modifiés ```text Cargo.toml crates/ksp-store-postgres-lib/tests/hardening_completeness.rs crates/ksp-store-postgres-lib/tests/postgres_raw_transaction_live.rs docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md ``` ## 14. Fichiers ajoutés ```text crates/ksp-store-postgres-lib/tests/postgres_raw_account_live.rs deltas/0.3.4/pre.009.md ``` Aucune suppression de fichier. ## 15. Validation exécutée dans l'environnement de génération ```text General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean Markdown table audit: clean ``` Cargo, rustfmt et PostgreSQL réel ne sont pas disponibles dans l'environnement de génération. Le gate opérateur standard et le live restent donc à exécuter localement. ## 16. Gate opérateur standard ```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.4 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 ``` ## 17. Gate PostgreSQL live opt-in Sur une base PostgreSQL dédiée et vide de toute table KSP gérée : ```bash printf '%s\n' '' | cargo test -p ksp-store-postgres-lib --test postgres_raw_account_live -- --ignored --nocapture --test-threads=1 ``` Le live `RawTransaction` peut ensuite être rejoué séparément sur une base de nouveau vide : ```bash printf '%s\n' '' | cargo test -p ksp-store-postgres-lib --test postgres_raw_transaction_live -- --ignored --nocapture --test-threads=1 ``` ## 18. Suite si les gates sont verts ```text 0.3.4-pre.010 — hardening/completeness cross-family ```