# Delta `0.3.3-pre.002` — moteur de migrations PostgreSQL multi-version ## 1. Base requise ```text 0.3.3-pre.001 ``` Le gate opérateur fourni pour `pre.001` est entièrement vert : ```text cargo fmt --all PASS audit Rust général / exports / workspace PASS audit Markdown PASS — 214 tables / 131 files cargo check --workspace PASS cargo clippy --workspace --all-targets PASS cargo test -p ksp-store-api PASS cargo test -p ksp-store-lib PASS cargo test -p ksp-store-postgres-lib PASS cargo test -p ksp-config-lib PASS cargo check -p ksp-store-lib --no-default-features PASS ``` Les tests live `#[ignore]` restent volontairement hors de ce gate ; `pre.001` était documentaire et `pre.002` ne crée encore aucun SQL métier V001. ## 2. Objectif Généraliser le bootstrap PostgreSQL V000 acquis en `0.3.2` vers un moteur embedded multi-version avant d'introduire la première migration métier. La tranche doit préserver : ```text checksum immuable mismatch terminal schema newer terminal aucun down automatique advisory transaction lock migration timeout statement timeout transaction unique metadata shape validation erreurs externes non rendues ``` Elle prépare également la frontière transactionnelle du futur binding `RawNetworkId`, sans créer V001 ni `ksp_store_identity`. ## 3. Version Le workspace passe à : ```text 0.3.3-pre.2 ``` ## 4. Registre embedded Le moteur ne possède plus une série de constantes spécialisées V000. Il utilise désormais : ```text EMBEDDED_MIGRATIONS: &[EmbeddedMigration] ``` Le registre réel de cette tranche contient exactement : ```text V000 bootstrap ``` Aucune V001 n'est anticipée dans les migrations physiques. Chaque entrée possède : ```text version name sql embedded migration hook ``` Le registre est validé avant I/O : ```text non vide commence à 0 versions contiguës strictement ordonnées name non vide SQL non vide ``` La version courante est dérivée du dernier élément du registre. ## 5. Validation d'historique multi-version L'historique PostgreSQL est maintenant validé comme **préfixe exact** du registre embedded. Cas : ```text historique exact complet -> prêt préfixe exact -> migrations pending nom divergent -> MigrationMismatch checksum divergent -> MigrationMismatch version/trou inattendu connu -> MigrationMismatch version > runtime courant -> SchemaNewer metadata existante sans V000 -> MigrationMismatch ``` Un préfixe exact n'est donc plus confondu avec une divergence : il représente précisément le cas normal d'upgrade V000 -> V001 attendu en `pre.003`. ## 6. Application des migrations pending Sous la transaction PostgreSQL et l'advisory lock déjà acquis : ```text load/validate history -> déterminer next_index -> refuser si pending && auto_migrate=false -> appliquer chaque migration dans l'ordre -> vérifier metadata shape -> exécuter migration hook -> insérer checksum/name/version dans history -> migration suivante -> commit unique ``` Une erreur à n'importe quelle étape provoque le rollback transactionnel normal ; aucune migration partiellement enregistrée n'est considérée appliquée. ## 7. Hook atomique de binding réseau `bootstrap` reçoit désormais le `RawNetworkId` du backend et le transmet jusqu'à chaque migration. Le moteur distingue deux contextes privés : ```text Existing migration déjà présente dans history à la réouverture AppliedNow migration exécutée pendant le bootstrap courant ``` Pour les migrations déjà appliquées, le hook est rejoué sous la transaction/advisory lock avant que le backend puisse être déclaré prêt. Pour une migration nouvellement appliquée, l'ordre est : ```text batch_execute(migration.sql) -> metadata shape check -> migration hook AppliedNow -> INSERT history -> commit final ``` V000 utilise : ```text MigrationHook::None ``` `pre.003` pourra donc ajouter le hook V001 `ksp_store_identity` avec deux comportements sûrs : création/validation en `AppliedNow`, validation stricte sans recréation en `Existing`. La frontière reste transactionnelle et ne crée aucune seconde phase de bootstrap race-prone. Aucune identité réseau n'est écrite dans cette tranche. ## 8. Compatibilité V000 Le fichier reste inchangé : ```text crates/ksp-store-postgres-lib/migrations/V000__bootstrap.sql ``` Checksum conservé : ```text d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450 ``` La metadata historique reste : ```text ksp_store_schema_migrations version BIGINT PRIMARY KEY name TEXT NOT NULL checksum TEXT NOT NULL applied_at TIMESTAMPTZ NOT NULL ``` ## 9. Tests du moteur Les unit tests `migration.rs` couvrent maintenant : ```text registre réel V000 immutable checksum V000 stable current version dérivée du registre registre synthétique V000/V001 ordonné historique V000 comme préfixe pending valide historique synthétique V000/V001 complet registre vide/non-zero/gap/name vide/SQL vide rejeté nom/checksum/history missing/gap rejetés version future -> SchemaNewer ``` Un canari d'intégration source vérifie aussi : ```text registre embedded présent hook de migration + contextes `AppliedNow`/`Existing` présents RawNetworkId transmis au hook validation préfixe utilisée application pending utilisée aucun V001__raw_transaction.sql aucun ksp_store_identity ``` ## 10. Fichiers modifiés ```text Cargo.toml crates/ksp-store-postgres-lib/src/migration.rs crates/ksp-store-postgres-lib/src/runtime.rs crates/ksp-store-postgres-lib/unit_tests/migration.rs crates/ksp-store-postgres-lib/tests/dependency_boundary.rs docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md ``` ## 11. Fichier ajouté ```text deltas/0.3.3/pre.002.md ``` ## 12. Fichiers supprimés Aucun. ## 13. Hors scope confirmé Aucun changement n'est apporté à : ```text V001 physique ksp_store_identity tables/indexes RawTransaction mapping Row/SQL métier six capabilities RawTransaction ksp-store-lib dispatch RawAccountState Config std.store workers/jobs/apps codecs wire ``` ## 14. Validations exécutées dans l'environnement de génération ```text python3 scripts/audit_rust_workspace_rules.py General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.3 Markdown table audit: clean ``` `cargo`, `rustc` et `rustfmt` ne sont pas disponibles dans l'environnement d'assemblage. Les validations Cargo ci-dessous restent donc opérateur et ne sont jamais déclarées PASS ici. ## 15. Gate opérateur demandé ```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 test PostgreSQL live n'est requis : le SQL physique reste strictement V000 et aucun schéma métier n'est introduit. ## 16. Suite Après gate vert, `0.3.3-pre.003` créera la vraie migration V001, les tables/constraints/indexes décidés en `pre.001` et le binding atomique `ksp_store_identity` via le hook préparé ici.