v0.3.3-pre.009-fix.005
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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('\'');
|
||||
|
||||
@@ -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");
|
||||
|
||||
128
deltas/0.3.3/pre.009-fix.005.md
Normal file
128
deltas/0.3.3/pre.009-fix.005.md
Normal 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
|
||||
```
|
||||
@@ -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`.
|
||||
|
||||
Reference in New Issue
Block a user