v0.3.3-pre.009-fix.005

This commit is contained in:
2026-08-30 15:46:03 +02:00
parent 5f1938c7c3
commit ba2e52f841
5 changed files with 183 additions and 15 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml
# version: 358
# version: 359
[workspace]
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.4"
version = "0.3.3-pre.9.fix.5"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/src/schema.rs
// version: 5
// version: 7
/// Immutable V000 physical schema resource inventory.
pub(crate) const V000_RESOURCES: &[SchemaResource] = &[SchemaResource {
@@ -1138,7 +1138,7 @@ fn matches_expected_constraint_definition(table: &str, kind: &str, definition: &
}
fn normalize_catalog_sql(value: &str) -> std::string::String {
let value = normalize_quoted_numeric_cast_literals(value);
let value = normalize_quoted_integral_cast_literals(value);
return value
.chars()
.filter(|character| return !character.is_whitespace() && *character != '"' && *character != '(' && *character != ')')
@@ -1147,11 +1147,15 @@ fn normalize_catalog_sql(value: &str) -> std::string::String {
.replace("::numeric", "")
.replace("::bigint", "")
.replace("::smallint", "")
.replace("::integer", "")
.replace("::int8", "")
.replace("::int4", "")
.replace("::int2", "")
.to_ascii_lowercase();
}
fn normalize_quoted_numeric_cast_literals(value: &str) -> std::string::String {
const NUMERIC_CAST: &str = "::numeric";
fn normalize_quoted_integral_cast_literals(value: &str) -> std::string::String {
const INTEGRAL_CASTS: &[&str] = &["::bigint", "::int2", "::int4", "::int8", "::integer", "::numeric", "::smallint"];
let mut normalized = std::string::String::with_capacity(value.len());
let mut remaining = value;
loop {
@@ -1172,15 +1176,24 @@ fn normalize_quoted_numeric_cast_literals(value: &str) -> std::string::String {
},
};
let has_digit = literal.chars().any(|character| return character.is_ascii_digit());
let numeric_literal = !literal.is_empty()
let integral_literal = !literal.is_empty()
&& has_digit
&& literal
.chars()
.enumerate()
.all(|(offset, character)| return character.is_ascii_digit() || (offset == 0 && (character == '+' || character == '-')));
if numeric_literal && let std::option::Option::Some(after_numeric_cast) = after_literal.strip_prefix(NUMERIC_CAST) {
let mut after_integral_cast = std::option::Option::None;
if integral_literal {
for cast in INTEGRAL_CASTS {
if let std::option::Option::Some(value) = after_literal.strip_prefix(*cast) {
after_integral_cast = std::option::Option::Some(value);
break;
}
}
}
if let std::option::Option::Some(value) = after_integral_cast {
normalized.push_str(literal);
remaining = after_numeric_cast;
remaining = value;
continue;
}
normalized.push('\'');

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-store-postgres-lib/unit_tests/schema.rs
// version: 3
// version: 4
fn actual_column(name: &str, udt_name: &str, nullable: bool) -> super::ActualColumn {
return super::ActualColumn {
@@ -101,6 +101,19 @@ fn pre_003_fix_001_catalog_normalization_and_resource_owned_constraint_definitio
assert_eq!(normalized, "checkslot>=0andslot<=18446744073709551615");
let postgres_17_normalized = super::normalize_catalog_sql("CHECK ((slot >= '0'::numeric) AND (slot <= '18446744073709551615'::numeric))");
assert_eq!(postgres_17_normalized, normalized);
let bigint_normalized = super::normalize_catalog_sql(
"CHECK ((block_time_unix_millis IS NULL) OR ((block_time_unix_millis >= '0'::bigint) AND (block_time_unix_millis <= '253402300799999'::bigint)))",
);
let block_time_resource = crate::V001_RESOURCES.iter().find(|resource| return resource.id == "constraints/007_ck_ksp_raw_transactions_block_time.sql");
assert!(block_time_resource.is_some(), "V001 block-time constraint resource must remain embedded");
let block_time_resource = match block_time_resource {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let block_time_expected = super::expected_constraint_definition(block_time_resource.sql, "ck_ksp_raw_transactions_block_time");
assert_eq!(block_time_expected.as_deref(), std::option::Option::Some(bigint_normalized.as_str()));
let integer_alias = super::normalize_catalog_sql("CHECK (format_version <= '4294967295'::int8)");
assert_eq!(integer_alias, "checkformat_version<=4294967295");
let text_literal = super::normalize_catalog_sql("CHECK (retention_state = 'full'::text)");
assert_eq!(text_literal, "checkretention_state='full'");
let resource = crate::V001_RESOURCES.iter().find(|resource| return resource.id == "constraints/006_ck_ksp_raw_transactions_slot.sql");

View File

@@ -0,0 +1,128 @@
<!-- file: deltas/0.3.3/pre.009-fix.005.md -->
<!-- version: 1 -->
# Delta `0.3.3-pre.009-fix.005` — canonicalisation des littéraux numériques/intégraux PostgreSQL
## 1. Base et diagnostic réel
Base opérateur :
```text
0.3.3-pre.9.fix.4
```
Le gate standard `pre.009-fix.004` fourni le 2026-08-30 est entièrement propre. Le live PostgreSQL 17 confirme que la correction du CHECK `slot` est effective puis avance jusqu'à la ressource suivante :
```text
constraints/007_ck_ksp_raw_transactions_block_time.sql
```
La ressource crée :
```sql
CHECK (
block_time_unix_millis IS NULL
OR block_time_unix_millis >= 0 AND block_time_unix_millis <= 253402300799999
)
```
`block_time_unix_millis` est `BIGINT`. `pg_get_constraintdef` reconstruit une expression depuis la représentation catalogue au lieu de restituer le texte SQL original ; une constante entière typée peut donc apparaître avec un cast explicite. La normalisation de `fix.004` savait retirer les quotes uniquement pour `::numeric` et pouvait encore considérer comme différente une forme telle que :
```text
'253402300799999'::bigint
```
## 2. Version
```text
workspace.package.version = 0.3.3-pre.9.fix.5
```
## 3. Correction d'introspection
`schema.rs` généralise la canonicalisation ciblée des littéraux entiers quotés. Une chaîne n'est déquotée que si :
- elle est constituée d'un signe ASCII optionnel suivi uniquement de chiffres ASCII ;
- elle est immédiatement suivie d'un cast numérique/intégral PostgreSQL retenu ;
- le cast appartient à `numeric`, `bigint`, `integer`, `smallint`, `int8`, `int4` ou `int2`.
Les casts équivalents non quotés sont également supprimés par la normalisation générale.
Cette règle reste volontairement distincte des littéraux métier/textuels :
```text
'full'::text
'archived'::text
'purged'::text
```
conservent leurs quotes dans la forme normalisée.
## 4. Canaris
Le test d'équivalence catalogue couvre désormais :
- le CHECK `slot` avec `'18446744073709551615'::numeric` ;
- le CHECK `block_time` avec `'0'::bigint` et `'253402300799999'::bigint` ;
- l'alias intégral `::int8` sur la borne `format_version` ;
- la préservation du littéral texte `'full'::text`.
Le but est de normaliser des représentations typées équivalentes, jamais de rendre un CHECK divergent compatible.
## 5. Pourquoi V001 reste inchangée
Comme pour `slot`, PostgreSQL applique la contrainte avant que KSP ne la rejette lors de la relecture post-apply. Le défaut reste donc dans l'équivalence de catalogue. Modifier le SQL V001 créerait une migration logique différente sans corriger la cause.
Checksums attendus inchangés :
```text
V000 d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450
V001 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51
```
## 6. Scope
Aucun changement de :
- ressource SQL V000/V001 ;
- ordre/nombre des 40 ressources V001 ;
- runtime RawTransaction ;
- pagination/cursor/rétention ;
- Store API/façade ;
- Config ;
- scope `RawAccountState`.
## 7. Fichiers modifiés
```text
Cargo.toml
crates/ksp-store-postgres-lib/src/schema.rs
crates/ksp-store-postgres-lib/unit_tests/schema.rs
docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md
deltas/0.3.3/pre.009-fix.005.md
```
Aucune suppression.
## 8. 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
```
Puis :
```bash
read -rsp "Dedicated PostgreSQL URI: " KSP_PG_TEST_URI; echo
printf '%s\n' "$KSP_PG_TEST_URI" | cargo test -p ksp-store-postgres-lib --test postgres_raw_transaction_live -- --ignored --nocapture --test-threads=1
unset KSP_PG_TEST_URI
```

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md -->
<!-- version: 18 -->
<!-- version: 19 -->
# Validation `0.3.3` — Store/PostgreSQL RawTransaction vertical slice
@@ -649,7 +649,11 @@ cap 500/1000 dans Store pagination
- 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 uniquement cette équivalence catalogue ciblée et ajoute un canari qui préserve les quotes des littéraux texte ; aucune ressource SQL/migration n'est modifiée.
- `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`
@@ -779,7 +783,17 @@ cargo check -p ksp-store-lib --no-default-features
- [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 statique] l'introspection normalise désormais uniquement les littéraux numériques quotés suivis de `::numeric`, forme que le déparseur PostgreSQL peut produire pour `NUMERIC` hors plage bigint ;
- [PASS statique] le canari couvre `'18446744073709551615'::numeric` et vérifie que les littéraux texte comme `'full'::text` conservent leurs quotes ;
- [PASS statique] aucun fichier SQL V000/V001, ordre de ressource ou checksum de migration n'est modifié ;
- [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`.