0.3.16-pre.3.fix.2

This commit is contained in:
2026-09-21 11:29:07 +02:00
parent 9a737ef57f
commit ec053c98ab
9 changed files with 157 additions and 22 deletions

View File

@@ -6,7 +6,7 @@ resolver = "3"
members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-raw-transaction-ingest-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"] members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-raw-transaction-ingest-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"]
[workspace.package] [workspace.package]
version = "0.3.16-pre.3.fix.1" version = "0.3.16-pre.3.fix.2"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/src/health.rs // file: crates/ksp-store-postgres-lib/src/health.rs
// version: 1 // version: 2
const DEFAULT_HEALTH_TIMEOUT_MS: u64 = 5_000; const DEFAULT_HEALTH_TIMEOUT_MS: u64 = 5_000;
const MIGRATION_VERSION_SQL: &str = "SELECT COALESCE(MAX(version), -1)::BIGINT FROM ksp_store_schema_migrations"; const MIGRATION_VERSION_SQL: &str = "SELECT COALESCE(MAX(version), -1)::BIGINT FROM ksp_store_schema_migrations";
@@ -61,7 +61,7 @@ async fn probe_health_inner(pool: &deadpool_postgres::Pool, runtime: crate::Post
return crate::PostgresBackendHealthSnapshot::not_ready(runtime, std::option::Option::None, 0, crate::PostgresBackendErrorKind::HealthFailed); return crate::PostgresBackendHealthSnapshot::not_ready(runtime, std::option::Option::None, 0, crate::PostgresBackendErrorKind::HealthFailed);
}, },
}; };
let expected = crate::current_migration_version(); let expected = crate::current_migration_version_v003();
if migration_version < 0 || migration_version < expected { if migration_version < 0 || migration_version < expected {
let observed = nonnegative_version(migration_version); let observed = nonnegative_version(migration_version);
let pending = pending_migration_count(migration_version, expected); let pending = pending_migration_count(migration_version, expected);

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/src/lib.rs // file: crates/ksp-store-postgres-lib/src/lib.rs
// version: 26 // version: 27
#![warn(missing_docs)] #![warn(missing_docs)]
#![deny(unreachable_pub)] #![deny(unreachable_pub)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
@@ -53,59 +53,112 @@ mod runtime;
mod schema; mod schema;
mod schema_v003; mod schema_v003;
/// Stable KSP error code for unsupported PostgreSQL retention compaction.
pub use self::error::ERROR_CODE_POSTGRES_RETENTION_COMPACTION_UNSUPPORTED; pub use self::error::ERROR_CODE_POSTGRES_RETENTION_COMPACTION_UNSUPPORTED;
/// Safe backend-local error returned to the common Store facade.
pub use self::error::PostgresBackendError; pub use self::error::PostgresBackendError;
/// Safe backend-local error classification used by the common Store facade.
pub use self::error::PostgresBackendErrorKind; pub use self::error::PostgresBackendErrorKind;
/// Opaque physical PostgreSQL backend owning its connection pool.
pub use self::runtime::PostgresBackend; pub use self::runtime::PostgresBackend;
/// Safe PostgreSQL readiness projection returned through the backend bridge.
pub use self::runtime::PostgresBackendHealthSnapshot; pub use self::runtime::PostgresBackendHealthSnapshot;
/// Safe PostgreSQL pool counter projection returned through the backend bridge.
pub use self::runtime::PostgresBackendRuntimeSnapshot; pub use self::runtime::PostgresBackendRuntimeSnapshot;
/// Physical PostgreSQL settings bridge consumed only by the backend crate.
pub use self::runtime::PostgresBackendSettings; pub use self::runtime::PostgresBackendSettings;
/// TLS mode accepted by the physical PostgreSQL settings bridge.
pub use self::runtime::PostgresBackendTlsMode; pub use self::runtime::PostgresBackendTlsMode;
/// Crate-owned tracing target for PostgreSQL backend behavior.
pub(crate) use self::constants::TRACING_TARGET; pub(crate) use self::constants::TRACING_TARGET;
/// Private bounded health probe consumed by the physical backend runtime.
pub(crate) use self::health::probe_health; pub(crate) use self::health::probe_health;
pub(crate) use self::migration::bootstrap as legacy_bootstrap; /// Frozen V000-V002 migration/bootstrap runner consumed only by the V003 extension.
pub(crate) use self::migration::current_migration_version as legacy_current_migration_version; pub(crate) use self::migration::bootstrap;
pub(crate) use self::migration_v003::bootstrap; /// Frozen V000-V002 latest migration version consumed only by the V003 extension.
pub(crate) use self::migration_v003::current_migration_version; pub(crate) use self::migration::current_migration_version;
/// Current V003 migration/bootstrap runner consumed by the physical backend runtime.
pub(crate) use self::migration_v003::bootstrap_v003;
/// Current embedded V003 migration version consumed by the private health probe.
pub(crate) use self::migration_v003::current_migration_version_v003;
/// Private RAW account cursor decoder consumed by the physical RAW account module.
pub(crate) use self::raw_account::cursor::decode_raw_account_cursor; pub(crate) use self::raw_account::cursor::decode_raw_account_cursor;
/// Private RAW account cursor encoder consumed by the physical RAW account module.
pub(crate) use self::raw_account::cursor::encode_raw_account_cursor; pub(crate) use self::raw_account::cursor::encode_raw_account_cursor;
/// Private physical account page-limit converter consumed by the physical RAW account module.
pub(crate) use self::raw_account::cursor::raw_account_physical_page_limit; pub(crate) use self::raw_account::cursor::raw_account_physical_page_limit;
/// Private RAW account observation reader consumed by the physical backend runtime.
pub(crate) use self::raw_account::get_raw_account_observation; pub(crate) use self::raw_account::get_raw_account_observation;
/// Private RAW account state reader consumed by the physical backend runtime.
pub(crate) use self::raw_account::get_raw_account_state; pub(crate) use self::raw_account::get_raw_account_state;
/// Private safe RAW account-observation inspection reader consumed by the physical backend runtime.
pub(crate) use self::raw_account::inspect_raw_account_observations; pub(crate) use self::raw_account::inspect_raw_account_observations;
/// Private data-free RAW account-state inspection reader consumed by the physical backend runtime.
pub(crate) use self::raw_account::inspect_raw_account_states; pub(crate) use self::raw_account::inspect_raw_account_states;
/// Private RAW account-state list reader consumed by the physical backend runtime.
pub(crate) use self::raw_account::list_raw_account_states; pub(crate) use self::raw_account::list_raw_account_states;
/// Private atomic RAW account acquisition writer consumed by the physical backend runtime.
pub(crate) use self::raw_account::persist_raw_account_acquisition; pub(crate) use self::raw_account::persist_raw_account_acquisition;
/// Private additional RAW account observation writer consumed by the physical backend runtime.
pub(crate) use self::raw_account::record_raw_account_observation; pub(crate) use self::raw_account::record_raw_account_observation;
/// Private RAW transaction cursor decoder consumed by the physical RAW module.
pub(crate) use self::raw_transaction::cursor::decode_raw_transaction_cursor; pub(crate) use self::raw_transaction::cursor::decode_raw_transaction_cursor;
/// Private RAW transaction cursor encoder consumed by the physical RAW module.
pub(crate) use self::raw_transaction::cursor::encode_raw_transaction_cursor; pub(crate) use self::raw_transaction::cursor::encode_raw_transaction_cursor;
/// Private physical page-limit converter consumed by the physical RAW module.
pub(crate) use self::raw_transaction::cursor::raw_transaction_physical_page_limit; pub(crate) use self::raw_transaction::cursor::raw_transaction_physical_page_limit;
/// Private RAW transaction reader consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::get_raw_transaction; pub(crate) use self::raw_transaction::get_raw_transaction;
/// Private RAW transaction observation reader consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::get_raw_transaction_observation; pub(crate) use self::raw_transaction::get_raw_transaction_observation;
/// Private RAW transaction retention-state reader consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::get_raw_transaction_retention_state; pub(crate) use self::raw_transaction::get_raw_transaction_retention_state;
/// Private RAW transaction tombstone reader consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::get_raw_transaction_tombstone; pub(crate) use self::raw_transaction::get_raw_transaction_tombstone;
/// Private safe RAW transaction-observation inspection reader consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::inspect_raw_transaction_observations; pub(crate) use self::raw_transaction::inspect_raw_transaction_observations;
/// Private payload-free RAW transaction inspection reader consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::inspect_raw_transactions; pub(crate) use self::raw_transaction::inspect_raw_transactions;
/// Private RAW transaction list reader consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::list_raw_transactions; pub(crate) use self::raw_transaction::list_raw_transactions;
/// Private atomic RAW transaction acquisition writer consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::persist_raw_transaction_acquisition; pub(crate) use self::raw_transaction::persist_raw_transaction_acquisition;
/// Private additional RAW transaction observation writer consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::record_raw_transaction_observation; pub(crate) use self::raw_transaction::record_raw_transaction_observation;
/// Private RAW transaction retention transition writer consumed by the physical backend runtime.
pub(crate) use self::raw_transaction::transition_raw_transaction_retention; pub(crate) use self::raw_transaction::transition_raw_transaction_retention;
/// Private Deadpool error mapper shared with the health probe.
pub(crate) use self::runtime::map_pool_error; pub(crate) use self::runtime::map_pool_error;
/// Private Deadpool status projector shared with the health probe.
pub(crate) use self::runtime::runtime_snapshot_from_status; pub(crate) use self::runtime::runtime_snapshot_from_status;
/// Private physical schema resource descriptor consumed by the frozen migration engine.
pub(crate) use self::schema::SchemaResource; pub(crate) use self::schema::SchemaResource;
/// Private physical schema resource compatibility state consumed by the frozen migration engine.
pub(crate) use self::schema::SchemaResourceState; pub(crate) use self::schema::SchemaResourceState;
/// Private V000 schema resource inventory consumed by the migration engines.
pub(crate) use self::schema::V000_RESOURCES; pub(crate) use self::schema::V000_RESOURCES;
/// Private V001 schema resource inventory consumed by the migration engines.
pub(crate) use self::schema::V001_RESOURCES; pub(crate) use self::schema::V001_RESOURCES;
/// Private V002 schema resource inventory consumed by the migration engines.
pub(crate) use self::schema::V002_RESOURCES; pub(crate) use self::schema::V002_RESOURCES;
/// Private physical schema resource inspector consumed by the migration engines.
pub(crate) use self::schema::inspect_resource; pub(crate) use self::schema::inspect_resource;
/// Private managed-schema adoption probe consumed by the frozen migration engine.
pub(crate) use self::schema::managed_schema_objects_exist; pub(crate) use self::schema::managed_schema_objects_exist;
/// Private V001 external-schema compatibility gate consumed by the migration engines.
pub(crate) use self::schema::verify_v001_external_compatibility; pub(crate) use self::schema::verify_v001_external_compatibility;
/// Private V002 external-schema compatibility gate consumed by the migration engines.
pub(crate) use self::schema::verify_v002_external_compatibility; pub(crate) use self::schema::verify_v002_external_compatibility;
/// Private V003 schema resource inventory consumed by the V003 migration extension.
pub(crate) use self::schema_v003::V003_RESOURCES; pub(crate) use self::schema_v003::V003_RESOURCES;
/// Private V003 schema resource descriptor consumed by the V003 migration extension.
pub(crate) use self::schema_v003::V003SchemaResource; pub(crate) use self::schema_v003::V003SchemaResource;
/// Private V003 schema compatibility state consumed by the V003 migration extension.
pub(crate) use self::schema_v003::V003SchemaResourceState; pub(crate) use self::schema_v003::V003SchemaResourceState;
/// Private V003 schema inspector consumed by the V003 migration extension.
pub(crate) use self::schema_v003::inspect_v003_resource; pub(crate) use self::schema_v003::inspect_v003_resource;
/// Private V003 external-schema compatibility gate consumed by the V003 migration extension.
pub(crate) use self::schema_v003::verify_v003_external_compatibility; pub(crate) use self::schema_v003::verify_v003_external_compatibility;
const _: &str = crate::TRACING_TARGET; const _: &str = crate::TRACING_TARGET;

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/src/migration_v003.rs // file: crates/ksp-store-postgres-lib/src/migration_v003.rs
// version: 2 // version: 3
use sha2::Digest; // rust-rules: trait-import use sha2::Digest; // rust-rules: trait-import
@@ -31,12 +31,12 @@ struct AppliedMigration {
/// Returns the latest migration version embedded by the physical PostgreSQL backend. /// Returns the latest migration version embedded by the physical PostgreSQL backend.
#[must_use] #[must_use]
pub(crate) const fn current_migration_version() -> i64 { pub(crate) const fn current_migration_version_v003() -> i64 {
return V003_VERSION; return V003_VERSION;
} }
/// Runs the frozen V000-V002 bootstrap followed by additive V003 under the KSP schema lock. /// Runs the frozen V000-V002 bootstrap followed by additive V003 under the KSP schema lock.
pub(crate) async fn bootstrap( pub(crate) async fn bootstrap_v003(
client: &mut deadpool_postgres::Client, client: &mut deadpool_postgres::Client,
network: &ksp_store_api::RawNetworkId, network: &ksp_store_api::RawNetworkId,
schema_autocreate: bool, schema_autocreate: bool,
@@ -44,7 +44,7 @@ pub(crate) async fn bootstrap(
migration_timeout: std::time::Duration, migration_timeout: std::time::Duration,
migration_lock_timeout: std::time::Duration, migration_lock_timeout: std::time::Duration,
) -> std::result::Result<(), crate::PostgresBackendError> { ) -> std::result::Result<(), crate::PostgresBackendError> {
if crate::legacy_current_migration_version() != 2 { if crate::current_migration_version() != 2 {
return std::result::Result::Err(crate::PostgresBackendError::new(crate::PostgresBackendErrorKind::MigrationMismatch, "v003_legacy_registry_version")); return std::result::Result::Err(crate::PostgresBackendError::new(crate::PostgresBackendErrorKind::MigrationMismatch, "v003_legacy_registry_version"));
} }
let metadata_result = metadata_exists_client(client).await; let metadata_result = metadata_exists_client(client).await;
@@ -67,7 +67,7 @@ pub(crate) async fn bootstrap(
return std::result::Result::Err(crate::PostgresBackendError::new(crate::PostgresBackendErrorKind::SchemaNewer, "history_newer")); return std::result::Result::Err(crate::PostgresBackendError::new(crate::PostgresBackendErrorKind::SchemaNewer, "history_newer"));
} }
if legacy_bootstrap_required(latest_before) { if legacy_bootstrap_required(latest_before) {
let legacy_result = crate::legacy_bootstrap(client, network, schema_autocreate, schema_autoupdate, migration_timeout, migration_lock_timeout).await; let legacy_result = crate::bootstrap(client, network, schema_autocreate, schema_autoupdate, migration_timeout, migration_lock_timeout).await;
if let std::result::Result::Err(error) = legacy_result { if let std::result::Result::Err(error) = legacy_result {
if error.kind() != crate::PostgresBackendErrorKind::SchemaNewer { if error.kind() != crate::PostgresBackendErrorKind::SchemaNewer {
return std::result::Result::Err(error); return std::result::Result::Err(error);

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/src/runtime.rs // file: crates/ksp-store-postgres-lib/src/runtime.rs
// version: 18 // version: 19
const APPLICATION_NAME: &str = "ksp-store"; const APPLICATION_NAME: &str = "ksp-store";
const MAX_CONNECTION_URI_BYTES: usize = 4_096; const MAX_CONNECTION_URI_BYTES: usize = 4_096;
@@ -298,7 +298,7 @@ impl PostgresBackend {
tls_mode = settings.tls_mode().code(), tls_mode = settings.tls_mode().code(),
"PostgreSQL Store backend established initial physical connection" "PostgreSQL Store backend established initial physical connection"
); );
let bootstrap_result = crate::bootstrap( let bootstrap_result = crate::bootstrap_v003(
&mut client, &mut client,
settings.network(), settings.network(),
settings.schema_autocreate, settings.schema_autocreate,

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/tests/v003_migration_completeness.rs // file: crates/ksp-store-postgres-lib/tests/v003_migration_completeness.rs
// version: 1 // version: 2
#![warn(missing_docs)] #![warn(missing_docs)]
#![deny(unreachable_pub)] #![deny(unreachable_pub)]
@@ -15,8 +15,10 @@ fn pre_003_v003_extension_is_wired_without_modifying_frozen_registry_sources() {
let extension = include_str!("../src/migration_v003.rs"); let extension = include_str!("../src/migration_v003.rs");
assert!(crate_root.contains("mod migration_v003;")); assert!(crate_root.contains("mod migration_v003;"));
assert!(crate_root.contains("mod schema_v003;")); assert!(crate_root.contains("mod schema_v003;"));
assert!(crate_root.contains("pub(crate) use self::migration_v003::bootstrap;")); assert!(crate_root.contains("pub(crate) use self::migration::bootstrap;"));
assert!(crate_root.contains("pub(crate) use self::migration_v003::current_migration_version;")); assert!(crate_root.contains("pub(crate) use self::migration::current_migration_version;"));
assert!(crate_root.contains("pub(crate) use self::migration_v003::bootstrap_v003;"));
assert!(crate_root.contains("pub(crate) use self::migration_v003::current_migration_version_v003;"));
assert!(legacy_migration.starts_with("// file: crates/ksp-store-postgres-lib/src/migration.rs\n// version: 10\n")); assert!(legacy_migration.starts_with("// file: crates/ksp-store-postgres-lib/src/migration.rs\n// version: 10\n"));
assert!(legacy_schema.starts_with("// file: crates/ksp-store-postgres-lib/src/schema.rs\n// version: 9\n")); assert!(legacy_schema.starts_with("// file: crates/ksp-store-postgres-lib/src/schema.rs\n// version: 9\n"));
assert!(!legacy_migration.contains("V003_RESOURCES")); assert!(!legacy_migration.contains("V003_RESOURCES"));

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/unit_tests/migration.rs // file: crates/ksp-store-postgres-lib/unit_tests/migration.rs
// version: 9 // version: 10
fn applied(version: i64, name: &str, checksum: &str) -> super::AppliedMigration { fn applied(version: i64, name: &str, checksum: &str) -> super::AppliedMigration {
return super::AppliedMigration { checksum: checksum.to_owned(), name: name.to_owned(), version }; return super::AppliedMigration { checksum: checksum.to_owned(), name: name.to_owned(), version };
@@ -51,7 +51,8 @@ fn pre_003_v002_registry_is_complete_and_keeps_v000_v001_checksums_stable() {
assert_eq!(v002.resources.len(), 32); assert_eq!(v002.resources.len(), 32);
assert_eq!(super::migration_checksum(v002), "ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e"); assert_eq!(super::migration_checksum(v002), "ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e");
assert!(super::validate_embedded_registry(super::EMBEDDED_MIGRATIONS).is_ok()); assert!(super::validate_embedded_registry(super::EMBEDDED_MIGRATIONS).is_ok());
assert_eq!(crate::current_migration_version(), 3); assert_eq!(crate::current_migration_version(), 2);
assert_eq!(crate::current_migration_version_v003(), 3);
let full = [ let full = [
applied(0, v000.name, super::migration_checksum(v000).as_str()), applied(0, v000.name, super::migration_checksum(v000).as_str()),
applied(1, v001.name, super::migration_checksum(v001).as_str()), applied(1, v001.name, super::migration_checksum(v001).as_str()),

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/unit_tests/migration_v003.rs // file: crates/ksp-store-postgres-lib/unit_tests/migration_v003.rs
// version: 2 // version: 3
fn applied(version: i64, name: &str, checksum: &str) -> super::AppliedMigration { fn applied(version: i64, name: &str, checksum: &str) -> super::AppliedMigration {
return super::AppliedMigration { checksum: checksum.to_owned(), name: name.to_owned(), version }; return super::AppliedMigration { checksum: checksum.to_owned(), name: name.to_owned(), version };
@@ -7,7 +7,7 @@ fn applied(version: i64, name: &str, checksum: &str) -> super::AppliedMigration
#[test] #[test]
fn pre_003_v003_extension_preserves_frozen_history_and_advances_current_version() { fn pre_003_v003_extension_preserves_frozen_history_and_advances_current_version() {
assert_eq!(crate::current_migration_version(), 3); assert_eq!(crate::current_migration_version_v003(), 3);
assert_eq!(super::V000_CHECKSUM, "d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450"); assert_eq!(super::V000_CHECKSUM, "d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450");
assert_eq!(super::V001_CHECKSUM, "31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51"); assert_eq!(super::V001_CHECKSUM, "31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51");
assert_eq!(super::V002_CHECKSUM, "ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e"); assert_eq!(super::V002_CHECKSUM, "ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e");

View File

@@ -0,0 +1,79 @@
<!-- file: deltas/0.3.16/pre.003-fix.002.md -->
<!-- version: 1 -->
# Delta `0.3.16-pre.003-fix.002` — façade crate-root V003 conforme aux audits
## Base requise
```text
0.3.16-pre.003-fix.001 appliquée
workspace.package.version = 0.3.16-pre.3.fix.1
```
Le gate opérateur de `pre.003-fix.001` confirme que `cargo check --workspace`, Clippy `-D warnings` et toutes les suites ciblées `ksp-store-postgres-lib` passent. Le fix précédent reste toutefois invalide au niveau des règles du workspace : 53 violations `RUST-DOC-102`, deux violations `RUST-IMPORT-104`, puis quatre candidats dérivés de l'audit d'exports.
## Version
Cette correction modifie du Rust :
```text
workspace.package.version = 0.3.16-pre.3.fix.2
```
## Corrections
Le correctif reste structurel et ne modifie aucune ressource SQL V003 :
- les rustdocs adjacentes de tous les reexports crate-root de `ksp-store-postgres-lib` sont restaurées ;
- aucun alias de `use` ou de reexport n'est utilisé ;
- les fonctions historiques V000-V002 restent inchangées dans `migration.rs` et sont réexportées sous leurs noms réels `crate::bootstrap` et `crate::current_migration_version` ;
- les fonctions de l'extension V003 deviennent explicitement `crate::bootstrap_v003` et `crate::current_migration_version_v003` ;
- `runtime.rs` et `health.rs` consomment explicitement les helpers V003 courants ;
- `migration_v003.rs` consomme les helpers historiques uniquement via la façade crate-root ;
- les canaris de migration distinguent explicitement la version legacy V002 de la version courante V003 ;
- le test de complétude confirme que `migration.rs` reste à sa version historique `10` et sans ressource V003.
## Invariants conservés
`crates/ksp-store-postgres-lib/src/migration.rs`, `src/schema.rs` et toutes les ressources sous `migrations/v000_*`, `migrations/v001_*`, `migrations/v002_*` et `migrations/v003_raw_transaction_variants/` restent inchangés par ce fix.
Le checksum V003 reste :
```text
3c9cf41877c96944a378abb41ee7a8d8ab7f99fc6dc2bb7a26c295cf8f9fc914
```
Aucun changement n'est apporté aux quatre tables V003, aux dix-huit contraintes, aux trois index, à la politique de backfill, à la sémantique `content_hash` ni à la logique de concurrence V002 -> V003.
## Validation exécutée lors de la génération
Les scripts Python réels du checkout complet ont été exécutés après application du fix :
```text
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
KSP workspace Rust rule audit: clean
Markdown table audit: clean (352 table(s), 947 file(s))
```
Le toolchain Rust n'est pas disponible dans l'environnement de génération ; les gates Cargo restent donc opérateur.
## Validation opérateur demandée
```bash
cargo fmt --all
cargo fmt --all -- --check
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
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p ksp-store-postgres-lib --all-targets --all-features
```
Les trois tests PostgreSQL live restent opt-in comme dans `pre.003`.
## Suite
Après gate propre : `0.3.16-pre.004` — backend PostgreSQL V003, bootstrap paresseux de l'identité, ledger de variantes, rattachement exact des nouvelles observations, idempotence et concurrence d'insertion.