From 12eaf7a3de03e66a64db9713092aabd56c21445a Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Sun, 30 Aug 2026 16:06:20 +0200 Subject: [PATCH] v0.3.3-pre.010 --- Cargo.toml | 2 +- .../tests/hardening_completeness.rs | 28 ++++- crates/ksp-store-lib/unit_tests/store.rs | 35 +++++- .../tests/hardening_completeness.rs | 48 +++++++- .../unit_tests/runtime.rs | 37 +++++- deltas/0.3.3/pre.010.md | 112 ++++++++++++++++++ ...3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md | 13 +- ...0-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md | 20 +++- 8 files changed, 283 insertions(+), 12 deletions(-) create mode 100644 deltas/0.3.3/pre.010.md diff --git a/Cargo.toml b/Cargo.toml index 6bf5bba..8a620ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.3.3-pre.9.fix.6" +version = "0.3.3-pre.10" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-store-lib/tests/hardening_completeness.rs b/crates/ksp-store-lib/tests/hardening_completeness.rs index d6f6bde..98a3cc8 100644 --- a/crates/ksp-store-lib/tests/hardening_completeness.rs +++ b/crates/ksp-store-lib/tests/hardening_completeness.rs @@ -1,5 +1,5 @@ // file: crates/ksp-store-lib/tests/hardening_completeness.rs -// version: 3 +// version: 4 #![warn(missing_docs)] #![deny(unreachable_pub)] @@ -261,3 +261,29 @@ fn pre_009_facade_production_sources_keep_config_env_physical_sql_and_backend_ha } return; } + +#[test] +fn pre_010_facade_raw_transaction_capability_inventory_is_exact_and_raw_account_scope_stays_closed() { + let store = include_str!("../src/store.rs"); + let capability_impls = [ + "impl ksp_store_api::RawTransactionRead for Store", + "impl ksp_store_api::RawTransactionWrite for Store", + "impl ksp_store_api::RawTransactionObservationRead for Store", + "impl ksp_store_api::RawTransactionObservationWrite for Store", + "impl ksp_store_api::RawTransactionRetentionRead for Store", + "impl ksp_store_api::RawTransactionRetentionWrite for Store", + ]; + for implementation in capability_impls { + assert_eq!(store.matches(implementation).count(), 1, "unexpected Store capability implementation inventory: {implementation}"); + } + for forbidden in [ + "impl ksp_store_api::RawAccountStateRead for Store", + "impl ksp_store_api::RawAccountStateWrite for Store", + "impl ksp_store_api::RawAccountObservationRead for Store", + "impl ksp_store_api::RawAccountObservationWrite for Store", + ] { + assert!(!store.contains(forbidden), "RawAccountState scope opened in Store during RawTransaction hardening: {forbidden}"); + } + assert_eq!(store.matches("validate_operation_network(").count(), 9); + return; +} diff --git a/crates/ksp-store-lib/unit_tests/store.rs b/crates/ksp-store-lib/unit_tests/store.rs index bc2ee93..229e4b9 100644 --- a/crates/ksp-store-lib/unit_tests/store.rs +++ b/crates/ksp-store-lib/unit_tests/store.rs @@ -1,5 +1,5 @@ // file: crates/ksp-store-lib/unit_tests/store.rs -// version: 5 +// version: 6 fn poll_ready(future: impl std::future::Future) -> T { let mut future = std::boxed::Box::pin(future); @@ -72,3 +72,36 @@ fn pre_008_operation_network_guard_rejects_mismatch_without_echoing_requested_ne assert!(!std::format!("{error:?}").contains("other-network")); return; } + +#[cfg(feature = "postgres")] +#[test] +fn pre_010_postgres_error_code_mapping_covers_every_current_backend_kind() { + let cases = [ + (ksp_store_postgres_lib::PostgresBackendErrorKind::ConfigInvalid, crate::ERROR_CODE_POSTGRES_CONFIG_INVALID), + (ksp_store_postgres_lib::PostgresBackendErrorKind::ConnectFailed, crate::ERROR_CODE_POSTGRES_CONNECT_FAILED), + (ksp_store_postgres_lib::PostgresBackendErrorKind::PoolTimeout, crate::ERROR_CODE_POSTGRES_POOL_TIMEOUT), + (ksp_store_postgres_lib::PostgresBackendErrorKind::HealthFailed, crate::ERROR_CODE_POSTGRES_HEALTH_FAILED), + (ksp_store_postgres_lib::PostgresBackendErrorKind::Conflict, ksp_store_api::ERROR_CODE_RAW_CONFLICT), + (ksp_store_postgres_lib::PostgresBackendErrorKind::DataInvalid, crate::ERROR_CODE_POSTGRES_DATA_INVALID), + (ksp_store_postgres_lib::PostgresBackendErrorKind::MigrationFailed, crate::ERROR_CODE_POSTGRES_MIGRATION_FAILED), + (ksp_store_postgres_lib::PostgresBackendErrorKind::PageLimitUnsupported, crate::ERROR_CODE_POSTGRES_PAGE_LIMIT_UNSUPPORTED), + (ksp_store_postgres_lib::PostgresBackendErrorKind::MigrationMismatch, crate::ERROR_CODE_POSTGRES_MIGRATION_MISMATCH), + (ksp_store_postgres_lib::PostgresBackendErrorKind::QueryInvalid, ksp_store_api::ERROR_CODE_RAW_QUERY_INVALID), + (ksp_store_postgres_lib::PostgresBackendErrorKind::ReadFailed, crate::ERROR_CODE_POSTGRES_READ_FAILED), + (ksp_store_postgres_lib::PostgresBackendErrorKind::ReferenceNotFound, crate::ERROR_CODE_RAW_REFERENCE_NOT_FOUND), + ( + ksp_store_postgres_lib::PostgresBackendErrorKind::RetentionCompactionUnsupported, + crate::ERROR_CODE_POSTGRES_RETENTION_COMPACTION_UNSUPPORTED, + ), + (ksp_store_postgres_lib::PostgresBackendErrorKind::SchemaNewer, crate::ERROR_CODE_POSTGRES_SCHEMA_NEWER), + (ksp_store_postgres_lib::PostgresBackendErrorKind::ShutdownTimeout, crate::ERROR_CODE_SHUTDOWN_TIMEOUT), + (ksp_store_postgres_lib::PostgresBackendErrorKind::TlsFailed, crate::ERROR_CODE_POSTGRES_TLS_FAILED), + (ksp_store_postgres_lib::PostgresBackendErrorKind::WriteFailed, crate::ERROR_CODE_POSTGRES_WRITE_FAILED), + (ksp_store_postgres_lib::PostgresBackendErrorKind::WrongNetwork, crate::ERROR_CODE_WRONG_NETWORK), + ]; + assert_eq!(cases.len(), 18); + for (kind, expected) in cases { + assert_eq!(super::postgres_error_code(kind), expected); + } + return; +} diff --git a/crates/ksp-store-postgres-lib/tests/hardening_completeness.rs b/crates/ksp-store-postgres-lib/tests/hardening_completeness.rs index 5c92115..c89ee76 100644 --- a/crates/ksp-store-postgres-lib/tests/hardening_completeness.rs +++ b/crates/ksp-store-postgres-lib/tests/hardening_completeness.rs @@ -1,5 +1,5 @@ // file: crates/ksp-store-postgres-lib/tests/hardening_completeness.rs -// version: 9 +// version: 10 #![warn(missing_docs)] #![deny(unreachable_pub)] @@ -255,3 +255,49 @@ fn pre_009_live_raw_transaction_proof_is_opt_in_isolated_and_secret_safe() { } return; } + +#[test] +fn pre_010_raw_transaction_capability_implementation_inventory_is_exact_and_raw_account_scope_stays_closed() { + let runtime = include_str!("../src/runtime.rs"); + let capability_impls = [ + "impl ksp_store_api::RawTransactionRead for PostgresBackend", + "impl ksp_store_api::RawTransactionWrite for PostgresBackend", + "impl ksp_store_api::RawTransactionObservationRead for PostgresBackend", + "impl ksp_store_api::RawTransactionObservationWrite for PostgresBackend", + "impl ksp_store_api::RawTransactionRetentionRead for PostgresBackend", + "impl ksp_store_api::RawTransactionRetentionWrite for PostgresBackend", + ]; + for implementation in capability_impls { + assert_eq!(runtime.matches(implementation).count(), 1, "unexpected PostgreSQL capability implementation inventory: {implementation}"); + } + for forbidden in [ + "impl ksp_store_api::RawAccountStateRead for PostgresBackend", + "impl ksp_store_api::RawAccountStateWrite for PostgresBackend", + "impl ksp_store_api::RawAccountObservationRead for PostgresBackend", + "impl ksp_store_api::RawAccountObservationWrite for PostgresBackend", + ] { + assert!(!runtime.contains(forbidden), "RawAccountState scope opened during RawTransaction hardening: {forbidden}"); + } + let migration = include_str!("../src/migration.rs"); + assert!(!migration.contains("ksp_raw_account")); + return; +} + +#[test] +fn pre_010_raw_transaction_private_sql_keeps_keyset_navigation_and_bounded_statement_surface() { + let source = include_str!("../src/raw_transaction.rs"); + for required in [ + "ORDER BY slot ASC, signature ASC", + "ORDER BY slot DESC, signature DESC", + "LIMIT $5", + "FOR UPDATE", + "ON CONFLICT DO NOTHING", + "ksp_raw_transaction_archive_payloads", + ] { + assert!(source.contains(required), "required hardened RawTransaction SQL contract missing: {required}"); + } + for forbidden in [" OFFSET ", "SELECT *", "ON CONFLICT DO UPDATE", "processing_state", "batch_size", "priority"] { + assert!(!source.contains(forbidden), "forbidden RawTransaction scope/policy SQL detected: {forbidden}"); + } + return; +} diff --git a/crates/ksp-store-postgres-lib/unit_tests/runtime.rs b/crates/ksp-store-postgres-lib/unit_tests/runtime.rs index 4caae98..859094b 100644 --- a/crates/ksp-store-postgres-lib/unit_tests/runtime.rs +++ b/crates/ksp-store-postgres-lib/unit_tests/runtime.rs @@ -1,5 +1,5 @@ // file: crates/ksp-store-postgres-lib/unit_tests/runtime.rs -// version: 4 +// version: 5 fn network() -> ksp_store_api::RawNetworkId { return match ksp_store_api::RawNetworkId::new("devnet") { @@ -124,3 +124,38 @@ fn pre_008_capability_error_mapping_uses_stable_store_and_store_api_codes() { } return; } + +#[test] +fn pre_010_capability_error_mapping_covers_every_current_backend_error_kind() { + let cases = [ + (crate::PostgresBackendErrorKind::ConfigInvalid, ksp_store_api::ErrorCode::new("store", "postgres_config_invalid")), + (crate::PostgresBackendErrorKind::ConnectFailed, ksp_store_api::ErrorCode::new("store", "postgres_connect_failed")), + (crate::PostgresBackendErrorKind::PoolTimeout, ksp_store_api::ErrorCode::new("store", "postgres_pool_timeout")), + (crate::PostgresBackendErrorKind::HealthFailed, ksp_store_api::ErrorCode::new("store", "postgres_health_failed")), + (crate::PostgresBackendErrorKind::Conflict, ksp_store_api::ERROR_CODE_RAW_CONFLICT), + (crate::PostgresBackendErrorKind::DataInvalid, ksp_store_api::ErrorCode::new("store", "postgres_data_invalid")), + (crate::PostgresBackendErrorKind::MigrationFailed, ksp_store_api::ErrorCode::new("store", "postgres_migration_failed")), + (crate::PostgresBackendErrorKind::PageLimitUnsupported, ksp_store_api::ErrorCode::new("store", "postgres_page_limit_unsupported")), + (crate::PostgresBackendErrorKind::MigrationMismatch, ksp_store_api::ErrorCode::new("store", "postgres_migration_mismatch")), + (crate::PostgresBackendErrorKind::QueryInvalid, ksp_store_api::ERROR_CODE_RAW_QUERY_INVALID), + (crate::PostgresBackendErrorKind::ReadFailed, ksp_store_api::ErrorCode::new("store", "postgres_read_failed")), + (crate::PostgresBackendErrorKind::ReferenceNotFound, ksp_store_api::ErrorCode::new("store", "raw_reference_not_found")), + (crate::PostgresBackendErrorKind::RetentionCompactionUnsupported, crate::ERROR_CODE_POSTGRES_RETENTION_COMPACTION_UNSUPPORTED), + (crate::PostgresBackendErrorKind::SchemaNewer, ksp_store_api::ErrorCode::new("store", "postgres_schema_newer")), + (crate::PostgresBackendErrorKind::ShutdownTimeout, ksp_store_api::ErrorCode::new("store", "shutdown_timeout")), + (crate::PostgresBackendErrorKind::TlsFailed, ksp_store_api::ErrorCode::new("store", "postgres_tls_failed")), + (crate::PostgresBackendErrorKind::WriteFailed, ksp_store_api::ErrorCode::new("store", "postgres_write_failed")), + (crate::PostgresBackendErrorKind::WrongNetwork, ksp_store_api::ErrorCode::new("store", "wrong_network")), + ]; + assert_eq!(cases.len(), 18); + for (kind, expected) in cases { + let backend = crate::PostgresBackendError::new(kind, "pre_010_safe_phase"); + let mapped = super::map_capability_error(backend); + assert_eq!(mapped.code(), expected); + let rendered = std::format!("{mapped:?}"); + assert!(rendered.contains("pre_010_safe_phase")); + assert!(!rendered.contains("postgresql://")); + assert!(!rendered.contains("SELECT ")); + } + return; +} diff --git a/deltas/0.3.3/pre.010.md b/deltas/0.3.3/pre.010.md new file mode 100644 index 0000000..ececbfa --- /dev/null +++ b/deltas/0.3.3/pre.010.md @@ -0,0 +1,112 @@ + + + +# Delta `0.3.3-pre.010` — hardening/completeness RawTransaction + +## 1. Base acquise + +Base opérateur : + +```text +0.3.3-pre.9.fix.6 +``` + +Le gate standard est entièrement propre et la preuve opt-in `postgres_raw_transaction_live` passe sur PostgreSQL 17. `pre.009`, corrections incluses, est donc fermée. + +## 2. Version + +```text +workspace.package.version = 0.3.3-pre.10 +``` + +## 3. Nature de la tranche + +`pre.010` est une tranche de hardening uniquement. Aucun fichier de production, aucune ressource SQL et aucune migration ne sont modifiés. + +Elle ajoute des canaris de complétude qui figent la vertical slice acquise avant le gate technique final. + +## 4. Conformance des six capacités + +Les tests exigent exactement une implémentation de chacun des traits suivants sur `PostgresBackend` puis sur `Store` : + +```text +RawTransactionRead +RawTransactionWrite +RawTransactionObservationRead +RawTransactionObservationWrite +RawTransactionRetentionRead +RawTransactionRetentionWrite +``` + +Le hardening refuse simultanément toute ouverture prématurée des quatre capacités `RawAccountState`/observation et toute ressource de migration `ksp_raw_account*`. + +## 5. Hardening SQL privé + +Le canari backend fige les propriétés physiques utiles à la vertical slice : + +- keyset ASC/DESC sur `(slot, signature)` ; +- `LIMIT` physique sans `OFFSET` ; +- `FOR UPDATE` pour les chemins concurrents ; +- `ON CONFLICT DO NOTHING` pour l’idempotence canonique ; +- archive payload séparée ; +- absence de `SELECT *`, `ON CONFLICT DO UPDATE`, `processing_state`, `batch_size` ou `priority`. + +Ce scan ne crée aucune policy worker dans Store. + +## 6. Mapping d’erreurs exhaustif + +Les 18 variantes actuelles de `PostgresBackendErrorKind` sont toutes exercées : + +- dans `ksp-store-postgres-lib`, vers le contrat `ksp-store-api` ; +- dans `ksp-store-lib`, vers les codes stables possédés par la façade. + +Le canari backend vérifie en plus que le rendu de l’erreur mappée ne contient ni URI PostgreSQL ni SQL. + +## 7. Migrations + +Inchangées : + +```text +V000 d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450 +V001 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51 +``` + +V001 reste à 40 ressources. + +## 8. Fichiers modifiés + +```text +Cargo.toml +crates/ksp-store-postgres-lib/tests/hardening_completeness.rs +crates/ksp-store-postgres-lib/unit_tests/runtime.rs +crates/ksp-store-lib/tests/hardening_completeness.rs +crates/ksp-store-lib/unit_tests/store.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.010.md +``` + +Aucune suppression. + +## 9. Gate opérateur attendu + +```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 +``` + +Aucun nouveau live PostgreSQL n’est requis en `pre.010`, car le runtime et les migrations sont byte-identiques à la base live validée `pre.009-fix.006`. + +## 10. Suite si le gate est vert + +```text +0.3.3-pre.011 — gate technique final +``` diff --git a/docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md b/docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md index ef16b68..4f81dc0 100644 --- a/docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md +++ b/docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md @@ -1,5 +1,5 @@ - + # Plan `0.3.3` — Store/PostgreSQL RawTransaction vertical slice @@ -1190,11 +1190,12 @@ Tranche matérialisée : ### `0.3.3-pre.010` — hardening/completeness -- scans boundaries ; -- hostile rows/cursors/errors ; -- inventaires modules/exports/deps ; -- conformance des six capacités ; -- absence de scope creep. +- inventaire exact des six implémentations `RawTransaction` dans le backend et la façade ; +- mapping exhaustif des 18 classes d’erreur PostgreSQL actuelles vers les codes Store/API stables ; +- canaris SQL privés : keyset, `LIMIT`, verrouillage/idempotence/rétention, absence de `OFFSET`/upsert divergent/policy worker ; +- maintien des scans boundaries, hostile rows/cursors/errors, modules/exports/deps ; +- fermeture explicite du scope `RawAccountState` dans runtime, façade et migrations ; +- aucun changement de production, migration ou checksum attendu. ### `0.3.3-pre.011` — gate technique final diff --git a/docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md b/docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md index 59bc4c9..d6b756c 100644 --- a/docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md +++ b/docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md @@ -1,5 +1,5 @@ - + # Validation `0.3.3` — Store/PostgreSQL RawTransaction vertical slice @@ -808,3 +808,21 @@ cargo check -p ksp-store-lib --no-default-features - [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`, `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 ; +- [À FAIRE] gate Cargo opérateur complet de `pre.010`. +