# Delta `0.3.17-pre.002` — contrats Store API conflict lifecycle et classification d'erreur ## Base requise ```text 0.3.17-pre.001 appliquée workspace.package.version = 0.3.17-pre.1 ``` Le gate opérateur reçu le 24 septembre 2026 est propre : ```text cargo fmt --all -- --check PASS 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), 965 file(s)) cargo check --workspace PASS, 6.11 s cargo clippy --workspace --all-targets --all-features -- -D warnings PASS, 25.28 s ``` ## Objet Figer la surface backend-neutral requise par le cycle de vie complet des variantes/conflits avant toute migration PostgreSQL V004. Cette tranche reste strictement dans `ksp-store-api` et ajoute : ```text inspection des variantes inspection des conflict cases participant ledger DTO historique append-only DTO/query actions compare-and-set à double revision outcomes stale/idempotent explicites StoreErrorClass Transient/Terminal StoreErrorClassifier backend-neutral ``` Elle ne modifie encore : ```text aucune migration SQL aucun backend PostgreSQL aucun ksp-store-lib aucun Worker aucun Transport/Config aucun Job Backfill aucune application Desk ``` ## Version workspace `Cargo.toml` : ```text header version : 652 -> 653 workspace : 0.3.17-pre.1 -> 0.3.17-pre.2 ``` ## Fichiers ajoutés ```text crates/ksp-store-api/src/capability/raw_conflict.rs crates/ksp-store-api/src/model/raw_conflict.rs crates/ksp-store-api/unit_tests/model/raw_conflict.rs deltas/0.3.17/pre.002.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-store-api/src/capability.rs crates/ksp-store-api/src/error.rs crates/ksp-store-api/src/lib.rs crates/ksp-store-api/src/model.rs crates/ksp-store-api/tests/dependency_boundary.rs crates/ksp-store-api/tests/external_backend.rs crates/ksp-store-api/tests/public_api.rs crates/ksp-store-api/tests/release_completeness.rs crates/ksp-store-api/tests/security_hardening.rs docs/validation/034-V0_3_17_RAW_OPERATIONAL_RESILIENCE.md ``` ## Contrats variantes La lecture opérateur des variantes est portée par : ```text RawTransactionVariantInspectionQuery RawTransactionVariantSummary RawTransactionVariantDetail RawTransactionVariantInspectionRead ``` La query est random-access bornée via `RawInspectionPageRequest`, exige un network et accepte seulement un filtre transaction exact cohérent avec ce network. Le summary reste payload-free et expose uniquement les métadonnées nécessaires : ```text variant reference origin slot / block_time format id/version retention state payload size si disponible is_current_canonical observation_count created_at ``` `RawTransactionVariantDetail` peut porter la transaction RAW complète uniquement dans la lecture explicite d'un variant. Le constructeur vérifie transaction identity, slot, block time, format et taille déclarée ; un variant `Purged` ne peut pas prétendre contenir encore le payload. ## Contrats conflict case Identité : ```text RawTransactionConflictReference -> RawTransactionReference ``` Inspection : ```text RawTransactionConflictInspectionQuery RawTransactionConflictSummary RawTransactionConflictParticipantSummary RawTransactionConflictDetail RawTransactionConflictInspectionRead ``` La projection courante conserve explicitement : ```text status Open/Resolved conflict revision > 0 canonical variant canonical selector revision > 0 latest incoming variant latest Conflict/Incomparable relation + reason resolved canonical variant si Resolved latest resolution action si Resolved participant_count >= 2 created_at / updated_at ``` Les références canonical/incoming/resolved doivent appartenir à la même transaction que le conflict case. Le detail valide que le participant ledger : ```text contient exactement participant_count entrées n'a aucun variant_id dupliqué reste dans le même scope transaction n'annonce aucun first_seen_revision > current conflict revision contient canonical/latest incoming/resolved target requis ``` ## Historique append-only Types ajoutés : ```text RawTransactionConflictEventKind RawTransactionConflictEventOrigin RawTransactionConflictEventSummary RawTransactionConflictHistoryQuery RawTransactionConflictHistoryRead ``` Event kinds figés : ```text Opened ParticipantAdded ResolvedKeepCanonical ResolvedPromoteVariant ResolvedRestoreVariant Reopened ``` Origins sûres : ```text Automatic Operator ``` Aucun acteur libre, texte backend, SQL ou payload RAW n'entre dans le DTO d'historique. Une transition de résolution exige exactement le `RawTransactionConflictResolutionAction` correspondant. `Opened` et `ParticipantAdded` exigent une comparaison durable `Conflict` ou `Incomparable`. ## Actions compare-and-set Types : ```text RawTransactionConflictResolutionAction RawTransactionConflictResolution RawTransactionConflictAction RawTransactionConflictActionRequest RawTransactionConflictActionOutcome RawTransactionConflictActionWrite ``` Actions disponibles : ```text KeepCurrentCanonical PromoteVariant(target) RestoreVariant(target) Resolve(explicit canonical resolution) Reopen ``` Chaque request transporte obligatoirement : ```text conflict reference expected_conflict_revision > 0 expected_canonical_revision > 0 action ``` Tout target variant doit appartenir à la transaction du conflict case. Outcomes backend-neutral : ```text Applied AlreadyAtTarget StaleRevision ConflictNotOpen ConflictNotResolved VariantNotParticipant VariantPayloadUnavailable ``` `AlreadyAtTarget` et `StaleRevision` restent volontairement distincts : une répétition idempotente n'est pas une perte de compare-and-set concurrente. ## Classification Store error `ksp-store-api` expose désormais : ```text StoreErrorClass::Transient StoreErrorClass::Terminal StoreErrorClassifier ``` Le classifier reçoit une `ksp_core_lib::Error` déjà projetée/redacted. Le Worker futur consommera ce contrat au lieu de comparer des codes PostgreSQL ou des chaînes libres. Cette tranche ne classe encore aucun SQLSTATE concret : le raffinement physique reste réservé à `pre.006`. La politique fail-closed définie par le plan reste inchangée : tout code non explicitement reconnu par l'implémentation future sera `Terminal`. ## Frontières préservées Le manifest `ksp-store-api` reste inchangé : ```text runtime dependency exacte = ksp-core-lib uniquement ``` Aucun nouveau crate externe n'est introduit. Tous les nouveaux items publics sont réexportés depuis la racine `ksp-store-api`; aucun `pub mod` n'est ajouté. Les enums évolutifs sont `#[non_exhaustive]`. Les capabilities restent object-safe et implémentables par un backend externe sans dépendre de `ksp-store-lib` ou PostgreSQL. ## Tests/canaris ajoutés ou étendus La tranche couvre statiquement et par tests Rust : ```text network coherence des queries variant/conflict double revision strictement positive scope transaction des targets d'action status Open/Resolved et projection resolution cohérente relation conflict/incomparable requise pour le conflict current participant ledger complet, unique et revision-safe history event/action consistency outcomes Applied/AlreadyAtTarget/StaleRevision distincts codes event/origin/resolution stables variant detail payload debug redacted object safety des quatre nouvelles capabilities + classifier inventaire exact crate-root/module/capability frontière dépendances backend-neutral #[non_exhaustive] des nouveaux enums ``` ## Validation locale de l'assemblage L'environnement d'assemblage ne fournit toujours pas `cargo`, `rustc` ou `rustfmt`. Aucun PASS Cargo n'est inventé pour `pre.002`. Audits réellement exécutés après les changements Rust : ```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), 966 file(s)) ``` Le gate Cargo utilisateur reste autoritaire pour confirmer compilation, rustfmt, Clippy et tests. ## Gate requis après application ```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-api --all-targets --all-features ``` Ne pas lancer de test PostgreSQL live pour cette tranche : aucune migration ni implémentation backend n'est encore modifiée. ## Prochaine tranche Après gate propre : ```text 0.3.17-pre.003 ``` Objet prévu : migration PostgreSQL V004 additive pour participants, historique append-only, projection de résolution et bootstrap legacy, avec canaris garantissant l'immuabilité byte/checksum de V000/V001/V002/V003.