14 KiB
Delta 0.3.3-pre.003-fix.001 — Store/PostgreSQL schema compatibility hardening
1. Base et objectif
Ce correctif s'applique par-dessus le commit 0.3.3-pre.003 déjà réalisé. Il ne réécrit ni ne remplace ce commit dans l'historique.
Le gate opérateur de pre.002 est vert. Le gate opérateur de pre.003 n'a pas été fourni avant l'ouverture de ce fix ; aucune commande Cargo du fix n'est donc déclarée PASS dans ce document.
Objectif du fix : conserver les bonnes garanties fonctionnelles historiques d'inspection/réconciliation du schéma PostgreSQL sans reprendre l'architecture kbot3, et corriger V001 avant l'ouverture du repository RawTransaction de pre.004.
Version workspace après application :
0.3.3-pre.3.fix.1
Identifiant de livraison :
0.3.3-pre.003-fix.001
2. Décisions corrigées
2.1 Migration logique vs ressources physiques
V000 et V001 restent des migrations logiques versionnées. Les objets physiques ne deviennent pas chacun une version de migration.
Arborescence retenue :
crates/ksp-store-postgres-lib/migrations/
v000_bootstrap/
tables/
001_ksp_store_schema_migrations.sql
v001_raw_transaction/
tables/
001_ksp_store_identity.sql
002_ksp_raw_transactions.sql
003_ksp_raw_transaction_observations.sql
004_ksp_raw_transaction_archive_payloads.sql
constraints/
001_...sql -> 035_...sql
indexes/
001_ix_ksp_raw_transactions_slot_signature.sql
V001 contient exactement :
4 tables
35 contraintes
1 index
40 ressources embedded
V000 est seulement déplacée : ses bytes restent strictement identiques.
2.2 Checksums
V000 historique :
d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450
V001 multi-ressources :
31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51
Le checksum V001 est calculé sur le préfixe de format du registre puis, dans l'ordre embedded, sur l'identifiant relatif et les bytes exacts de chaque ressource. Le checksum monolithique pre.003 n'est pas réutilisé.
Une base ayant réellement enregistré l'ancien checksum V001 du commit pre.003 n'est jamais réécrite silencieusement : elle doit être réinitialisée si elle est jetable ou réconciliée manuellement.
2.3 IF NOT EXISTS n'est pas une preuve de compatibilité
Les ressources utilisent CREATE ... IF NOT EXISTS, ADD COLUMN IF NOT EXISTS ou des guards catalogue lorsque cela permet une création additive idempotente.
Après et avant mutation, le backend introspecte néanmoins le catalogue PostgreSQL. Chaque ressource est classée :
Compatible
Missing
Incompatible
Un objet préexistant du bon nom mais de mauvaise définition est donc refusé.
2.4 Contrat physique vérifié
Le module backend-private schema contrôle notamment :
- tables gérées et nature
BASE TABLE; - colonnes obligatoires, type, nullabilité et absence d'identity/generated sur le contrat KSP ;
- précision/scale
NUMERIC(20,0)du slot ; - PK, FK et CHECK ;
- définition canonique des contraintes à partir de leur propre ressource SQL ;
- index partiel
(slot, signature)horspurged; - RLS ;
- triggers utilisateur actifs ;
- rewrite rules ;
- contraintes/indexes uniques externes susceptibles de modifier la sémantique de write.
Les marqueurs COMMENT ne servent pas de preuve de compatibilité et ne sont pas requis.
2.5 Extensions externes compatibles
KSP ne requiert pas une égalité byte-for-byte du schéma complet avec son propre DDL. Les extensions externes qui sont prouvées non bloquantes restent admises.
Le correctif tolère notamment :
- une colonne externe nullable, sans default, identity ni generated expression ;
- un index externe non unique ;
- une contrainte attendue physiquement équivalente même si son nom diffère.
Le correctif bloque conservativement les extensions susceptibles de modifier/contraindre les writes KSP lorsqu'il ne peut pas en prouver l'innocuité : mauvais type/nullabilité sur une colonne KSP, colonne externe write-blocking, contrainte non équivalente, unique index autonome, trigger actif, rule ou RLS.
2.6 Politiques schema_autocreate / schema_autoupdate
std.store passe en format V2 et sépare :
schema_autocreate
schema_autoupdate
schema_autocreate autorise l'initialisation ou l'adoption contrôlée d'une base sans metadata KSP.
schema_autoupdate autorise les migrations pending et les réparations additives sûres de ressources manquantes sur un schéma KSP existant.
Une incompatibilité exigeant une mutation destructive, ambiguë ou non prouvée sûre reste bloquante même avec schema_autoupdate=true; le backend émet uniquement une phase/resource sûre pour permettre l'intervention manuelle.
Le format V1 reste lisible : auto_migrate est mappé vers les deux politiques. Les constructeurs Rust historiques restent également disponibles et mappent leur booléen vers les deux politiques.
2.7 Identité réseau
Le binding V001 reste sous la même transaction et le même advisory lock.
Une ksp_store_identity absente alors que V001 est déjà enregistrée n'est jamais reconstruite automatiquement, même avec schema_autoupdate=true, afin d'interdire tout rebind réseau silencieux.
3. Suppressions explicites après application de l'overlay
L'extraction d'un zip n'efface pas les anciens fichiers. Après extraction du delta à la racine du dépôt, supprimer explicitement :
rm crates/ksp-store-postgres-lib/migrations/V000__bootstrap.sql
rm crates/ksp-store-postgres-lib/migrations/V001__raw_transaction.sql
Fichiers supprimés :
crates/ksp-store-postgres-lib/migrations/V000__bootstrap.sqlcrates/ksp-store-postgres-lib/migrations/V001__raw_transaction.sql
4. Fichiers modifiés
Cargo.tomlconfig/examples/std.store.example.jsonconfig/schemas/std.store.schema.jsonconfig/std.store.jsoncrates/ksp-config-lib/src/store.rscrates/ksp-config-lib/unit_tests/fixtures/std.store.jsoncrates/ksp-config-lib/unit_tests/store.rscrates/ksp-store-lib/src/settings.rscrates/ksp-store-lib/src/store.rscrates/ksp-store-lib/unit_tests/settings.rscrates/ksp-store-postgres-lib/src/lib.rscrates/ksp-store-postgres-lib/src/migration.rscrates/ksp-store-postgres-lib/src/runtime.rscrates/ksp-store-postgres-lib/tests/dependency_boundary.rscrates/ksp-store-postgres-lib/tests/hardening_completeness.rscrates/ksp-store-postgres-lib/unit_tests/migration.rsdocs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.mddocs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md
5. Fichiers ajoutés
crates/ksp-store-postgres-lib/migrations/v000_bootstrap/tables/001_ksp_store_schema_migrations.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/001_pk_ksp_store_identity.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/002_ck_ksp_store_identity_singleton.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/003_ck_ksp_store_identity_network.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/004_pk_ksp_raw_transactions.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/005_ck_ksp_raw_transactions_signature.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/006_ck_ksp_raw_transactions_slot.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/007_ck_ksp_raw_transactions_block_time.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/008_ck_ksp_raw_transactions_format_id.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/009_ck_ksp_raw_transactions_format_version.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/010_ck_ksp_raw_transactions_content_hash.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/011_ck_ksp_raw_transactions_payload.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/012_ck_ksp_raw_transactions_retention_state.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/013_ck_ksp_raw_transactions_payload_state.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/014_ck_ksp_raw_transactions_purged_block_time.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/015_pk_ksp_raw_transaction_observations.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/016_fk_ksp_raw_transaction_observations_transaction.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/017_ck_ksp_raw_transaction_observations_key.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/018_ck_ksp_raw_transaction_observations_signature.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/019_ck_ksp_raw_transaction_observations_provider.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/020_ck_ksp_raw_transaction_observations_protocol.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/021_ck_ksp_raw_transaction_observations_method.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/022_ck_ksp_raw_transaction_observations_origin.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/023_ck_ksp_raw_transaction_observations_received_at.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/024_ck_ksp_raw_transaction_observations_capture_session.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/025_ck_ksp_raw_transaction_observations_commitment.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/026_ck_ksp_raw_transaction_observations_endpoint.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/027_ck_ksp_raw_transaction_observations_filter.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/028_ck_ksp_raw_transaction_observations_observed_at.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/029_ck_ksp_raw_transaction_observations_time_order.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/030_ck_ksp_raw_transaction_observations_source_hash.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/031_ck_ksp_raw_transaction_observations_source_size.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/032_pk_ksp_raw_transaction_archive_payloads.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/033_fk_ksp_raw_transaction_archive_payloads_transaction.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/034_ck_ksp_raw_transaction_archive_payloads_signature.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/constraints/035_ck_ksp_raw_transaction_archive_payloads_payload.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/indexes/001_ix_ksp_raw_transactions_slot_signature.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/tables/001_ksp_store_identity.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/tables/002_ksp_raw_transactions.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/tables/003_ksp_raw_transaction_observations.sqlcrates/ksp-store-postgres-lib/migrations/v001_raw_transaction/tables/004_ksp_raw_transaction_archive_payloads.sqlcrates/ksp-store-postgres-lib/src/schema.rscrates/ksp-store-postgres-lib/unit_tests/schema.rsdeltas/0.3.3/pre.003-fix.001.md
6. Validation de génération
Les validations réalisables dans l'environnement de génération doivent être propres avant publication de l'archive :
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
validation JSON/JSON Schema std.store V1+V2
inventaire/checksum migration V000/V001
L'environnement de génération ne possède pas cargo/rustfmt. Les gates Cargo ci-dessous restent donc NON EXÉCUTÉS jusqu'au passage opérateur.
7. Gate opérateur demandé
Après extraction de l'overlay, suppression explicite des deux fichiers monolithiques puis application du formatage :
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
Canaris de suppression :
test ! -e crates/ksp-store-postgres-lib/migrations/V000__bootstrap.sql
test ! -e crates/ksp-store-postgres-lib/migrations/V001__raw_transaction.sql
Le vrai PostgreSQL live du contrat V001, des dérives et des réparations reste volontairement réservé au gate live prévu plus tard dans 0.3.3; ce fix ne le présente pas comme PASS.
8. Suite
Après gate opérateur vert de pre.003-fix.001, reprendre le séquencement avec :
0.3.3-pre.004 — mapping SQL privé + lectures RawTransaction/observation/rétention/tombstone