# Delta `0.3.3-pre.009` — preuve PostgreSQL live complète RawTransaction ## 1. Base et gate d'entrée Base opérateur obligatoire : ```text 0.3.3-pre.8.fix.1 ``` Le gate opérateur fourni le 2026-08-30 est entièrement propre : audits Rust/Markdown, `cargo check --workspace`, Clippy all-targets sans warning, tests Store API/façade/PostgreSQL/Config et `ksp-store-lib --no-default-features` passent. `pre.008-fix.001` est donc acquise. ## 2. Version ```text workspace.package.version = 0.3.3-pre.9 ``` ## 3. Nouveau test PostgreSQL réel La tranche ajoute : ```text crates/ksp-store-postgres-lib/tests/postgres_raw_transaction_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 existe déjà. Il ne nettoie que le schéma qu'il a prouvé absent avant son propre bootstrap. Il refuse PostgreSQL < 15 comme la preuve fondation existante. ## 4. Migration, identité réseau et schema update La preuve couvre : - bootstrap V000 + V001 sur base vide ; - health Ready avec migration 1 ; - refus d'une réouverture sous un autre `RawNetworkId` ; - réouverture idempotente ; - suppression contrôlée de `ix_ksp_raw_transactions_slot_signature` ; - `schema_autoupdate=false` qui bloque le drift ; - `schema_autoupdate=true` qui recrée et revalide l'index manquant. Aucune ressource de migration n'est modifiée et aucun historique n'est réécrit. ## 5. Écriture, idempotence, concurrence et rollback Le live couvre : - canonical + observation atomiques ; - get canonical exact ; - observation round-trip exact avec provenance complète ; - deux acquisitions identiques en vraies tâches concurrentes : un `Inserted`, un `AlreadyPresent` ; - deux acquisitions divergentes sous la même signature : un gagnant et un `Conflict` ; - vérification qu'une seule observation du duel divergent est durable ; - observation supplémentaire `Inserted` puis `AlreadyPresent` ; - même observation key divergente -> `Conflict` ; - collision observation pendant une nouvelle acquisition -> rollback du canonical nouvellement tenté. ## 6. Pagination Le test insère cinq signatures sur trois slots, dont deux paires ex æquo, et prouve : ```text Ascending 50, 51, 52, 53, 54 Descending 54, 53, 52, 51, 50 page size 2 ``` Il rejoue ensuite le cursor V1 sous : - direction différente ; - range différente. Les deux cas doivent être `QueryInvalid`. ## 7. Rétention et rehydrate La preuve couvre : - compare mismatch observable ; - `Full -> Archived` et lecture exacte depuis archive ; - idempotence `AlreadyAtTarget` ; - `Archived -> Purged` ; - `get -> None` et tombstone minimal exact ; - acquisition normale sur tombstone -> `SkippedPurged/NotRecorded` ; - ForceRehydrate divergent -> `Conflict` sans mutation ; - ForceRehydrate compatible -> `Rehydrated/Inserted` ; - `Full -> Compacted` rejeté par `RetentionCompactionUnsupported` sans changement d'état ; - deux archives concurrentes puis deux purges concurrentes : un `Applied` et un `AlreadyAtTarget` par race ; - rehydrate après la race purge. ## 8. Cancellation réelle Le test crée une observation durable, la verrouille via une transaction PostgreSQL administrateur, puis démarre une nouvelle acquisition qui : 1. insère son canonical dans sa transaction non committée ; 2. bloque sur la collision de l'observation verrouillée ; 3. reste bloquée au-delà du délai canari ; 4. est annulée via `JoinHandle::abort()` ; 5. libère ensuite le verrou administrateur ; 6. prouve que le canonical de l'acquisition annulée n'est pas durable. Cette preuve exerce un rollback par cancellation réelle, pas une simulation séquentielle. ## 9. Réouverture finale Après toutes les opérations, le backend est rouvert sur le même réseau. Le test exige : - health Ready ; - migration 1 ; - lecture exacte d'un canonical durable antérieur. Le cleanup final supprime les cinq tables KSP uniquement parce que leur absence initiale a été prouvée. ## 10. Migrations Aucune ressource V000/V001 n'est modifiée. Checksums attendus et recalculés : ```text V000 d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450 V001 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51 ``` V001 reste exactement à 40 ressources. ## 11. Fichiers modifiés ```text Cargo.toml crates/ksp-store-postgres-lib/README.md crates/ksp-store-postgres-lib/USAGE.md crates/ksp-store-postgres-lib/tests/hardening_completeness.rs crates/ksp-store-postgres-lib/tests/postgres_raw_transaction_live.rs docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md deltas/0.3.3/pre.009.md ``` Aucune suppression de fichier. ## 12. 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 et le live restent donc à exécuter localement. ## 13. 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.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 ``` ## 14. 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_transaction_live -- --ignored --nocapture ``` ## 15. Suite si les deux gates sont verts ```text 0.3.3-pre.010 — hardening/completeness ```