0.3.16-pre.008
This commit is contained in:
236
deltas/0.3.16/pre.008.md
Normal file
236
deltas/0.3.16/pre.008.md
Normal file
@@ -0,0 +1,236 @@
|
||||
<!-- file: deltas/0.3.16/pre.008.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.16-pre.008` — hardening technique de la vertical slice variantes/conflits
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.16-pre.007-fix.003 appliqué
|
||||
workspace.package.version = 0.3.16-pre.7.fix.3
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.007-fix.003` est entièrement propre : format, audits Rust/Markdown, `cargo check --workspace`, Clippy workspace/all-targets/all-features, Store API, Store façade, PostgreSQL, Job Backfill et l'intégralité des suites ciblées du Worker passent. `pre.007` est donc fermé avant ouverture de cette tranche.
|
||||
|
||||
## Objectif
|
||||
|
||||
`pre.008` est la tranche de hardening technique finale de la vertical slice `0.3.16` :
|
||||
|
||||
```text
|
||||
concurrence même identité
|
||||
rollback transactionnel promotion/conflit
|
||||
cohérence projection V001 / selector V003
|
||||
conservation du canonique en conflit
|
||||
régressions Job Backfill / Worker
|
||||
preuves live PostgreSQL opt-in actualisées
|
||||
gate workspace
|
||||
```
|
||||
|
||||
Aucune nouvelle capacité fonctionnelle, résolution opérateur, retry Store, reconnexion Transport ou Store Desk n'est introduite.
|
||||
|
||||
## Version
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.16-pre.8
|
||||
```
|
||||
|
||||
## Hardening PostgreSQL statique
|
||||
|
||||
Les canaris V003 verrouillent désormais explicitement deux invariants supplémentaires :
|
||||
|
||||
1. la branche `ActiveConflict` persiste/réutilise la variante entrante et ouvre/complète le conflict case, mais n'appelle jamais la promotion canonique et ne touche ni `UPDATE_CANONICAL_TRANSACTION_PROJECTION_SQL` ni `UPDATE_TRANSACTION_VARIANT_SELECTOR_SQL` ;
|
||||
2. les helpers de promotion et de conflict case reçoivent la transaction PostgreSQL de l'acquisition et ne peuvent jamais effectuer leur propre `COMMIT`.
|
||||
|
||||
Les gardes existantes restent exigées :
|
||||
|
||||
```text
|
||||
identity row -> FOR UPDATE
|
||||
selector promotion -> expected canonical_variant_id + expected canonical_revision
|
||||
conflict update -> expected revision
|
||||
```
|
||||
|
||||
Ainsi, selector, projection V001, ledger V003, conflict case, observation et mapping restent bornés par la transaction d'acquisition externe.
|
||||
|
||||
## Preuve live PostgreSQL actualisée
|
||||
|
||||
Le test opt-in `postgres_raw_transaction_live.rs` est réaligné sur la sémantique `pre.007`.
|
||||
|
||||
Le scénario de divergence concurrente d'une même identité attend désormais :
|
||||
|
||||
```text
|
||||
1 x InsertedCanonical
|
||||
1 x QuarantinedConflict
|
||||
2 variantes durables
|
||||
2 observations durables
|
||||
2 mappings observation -> variante
|
||||
1 selector canonique
|
||||
1 conflict case Open revision 1
|
||||
projection V001 == variante désignée par le selector
|
||||
```
|
||||
|
||||
L'ordre d'arrivée n'est pas supposé : l'une ou l'autre acquisition peut devenir le premier canonique, mais la seconde doit être quarantinée sans écraser ce canonique.
|
||||
|
||||
### Rollback après ouverture réelle d'un conflit
|
||||
|
||||
Un nouveau scénario live force une erreur après les écritures de divergence mais avant le commit :
|
||||
|
||||
```text
|
||||
canonique existant
|
||||
-> incoming divergent
|
||||
-> variante entrante créée
|
||||
-> conflict case créé
|
||||
-> collision volontaire d'observation avec une autre identité
|
||||
-> erreur avant COMMIT
|
||||
-> rollback implicite de la transaction
|
||||
```
|
||||
|
||||
Après l'échec, la preuve exige exactement l'état antérieur :
|
||||
|
||||
```text
|
||||
1 seule variante pour l'identité
|
||||
1 selector
|
||||
0 conflict case
|
||||
1 observation de seed
|
||||
1 mapping de seed
|
||||
projection V001 toujours cohérente avec le selector
|
||||
```
|
||||
|
||||
Cela couvre le risque qu'un conflict case ou une variante orpheline survive à un échec tardif de l'acquisition.
|
||||
|
||||
Le test live reste `#[ignore]`, lit uniquement un URI PostgreSQL dédié depuis stdin, refuse un schéma KSP préexistant et ne devient pas un gate automatique sans ressource opérateur explicite.
|
||||
|
||||
## Régression Job Backfill
|
||||
|
||||
Le Job Backfill ajoute un canari sur une réobservation déjà idempotente d'un conflit durable :
|
||||
|
||||
```text
|
||||
entity = AlreadyPresent
|
||||
observation = AlreadyPresent
|
||||
variant = QuarantinedConflict
|
||||
```
|
||||
|
||||
La projection doit rester :
|
||||
|
||||
```text
|
||||
BackfillEntityPersistence::Conflict
|
||||
BackfillObservationPersistence::AlreadyPresent
|
||||
```
|
||||
|
||||
Le conflit durable n'est donc jamais aplati en simple `AlreadyPresent`, même lorsque l'observation est elle-même idempotente.
|
||||
|
||||
## Régression Worker
|
||||
|
||||
Le Worker ajoute une preuve runtime avec deux identités successives alors que le Store retourne `QuarantinedConflict` :
|
||||
|
||||
```text
|
||||
première identité -> QuarantinedConflict
|
||||
seconde identité -> QuarantinedConflict
|
||||
```
|
||||
|
||||
Les deux acquisitions doivent atteindre le Store. Après les deux résultats :
|
||||
|
||||
```text
|
||||
state = Running
|
||||
health = Degraded
|
||||
persisted_total = 2
|
||||
content_conflict_total = 2
|
||||
store_failure_total = 0
|
||||
```
|
||||
|
||||
Le Stop explicite doit ensuite terminer en `Stopped`. Cette preuve verrouille directement l'invariant « un conflit durable n'empêche pas la progression d'une autre identité ».
|
||||
|
||||
## Recalibrage du lifecycle de fermeture
|
||||
|
||||
Le plan 038 est ajusté pour respecter les règles `VER-LIFECYCLE` actuelles, qui sont plus strictes que le découpage historique `pre.008 -> rel.001` :
|
||||
|
||||
```text
|
||||
pre.008 = hardening / gate technique
|
||||
pre.009 = réconciliation documentaire finale
|
||||
pre.010 = préparation minimale de publication
|
||||
rel.001 = mécanique de publication stable
|
||||
```
|
||||
|
||||
`pre.008` ne modifie donc ni `CHANGELOG.md`, ni `ROADMAP.md`, ni le prompt de démarrage suivant, et ne fait pas la réconciliation README/USAGE finale.
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-job-backfill-lib/unit_tests/persistence.rs
|
||||
crates/ksp-store-postgres-lib/tests/hardening_completeness.rs
|
||||
crates/ksp-store-postgres-lib/tests/postgres_raw_transaction_live.rs
|
||||
crates/ksp-store-postgres-lib/tests/v003_variant_persistence.rs
|
||||
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime.rs
|
||||
docs/plans/038-V0_3_16_RAW_RESILIENCE_CONFLICT_PLAN.md
|
||||
```
|
||||
|
||||
## Fichier ajouté
|
||||
|
||||
```text
|
||||
deltas/0.3.16/pre.008.md
|
||||
```
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
```text
|
||||
aucun
|
||||
```
|
||||
|
||||
## Validations exécutées lors de la génération
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
Le toolchain Rust n'est pas installé dans l'environnement de génération. `cargo fmt`, `cargo check`, Clippy et les tests Cargo ne sont donc pas déclarés exécutés ici.
|
||||
|
||||
La preuve PostgreSQL live reste volontairement opt-in et n'est pas déclarée exécutée sans URI isolé fourni par l'opérateur.
|
||||
|
||||
## Gate opérateur demandé
|
||||
|
||||
```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
|
||||
cargo test -p ksp-store-lib --all-targets --all-features
|
||||
cargo test -p ksp-store-postgres-lib --all-targets --all-features
|
||||
cargo test -p ksp-job-backfill-lib --all-targets --all-features
|
||||
cargo test -p ksp-worker-raw-transaction-ingest-lib --all-targets --all-features
|
||||
```
|
||||
|
||||
Le live PostgreSQL peut être exécuté séparément sur une base dédiée vide :
|
||||
|
||||
```bash
|
||||
cargo test -p ksp-store-postgres-lib --test postgres_raw_transaction_live -- --ignored --nocapture
|
||||
```
|
||||
|
||||
Il ne doit jamais être lancé contre une base KSP contenant des données utiles.
|
||||
|
||||
## Décisions prises
|
||||
|
||||
- aucune modification runtime n'est nécessaire pour fermer le hardening observé ;
|
||||
- le conflit durable concurrent est un succès quarantiné, pas une erreur backend ;
|
||||
- les deux observations concurrentes divergentes doivent être conservées ;
|
||||
- un échec tardif avant commit doit annuler variante et conflict case nouvellement créés ;
|
||||
- le canonique ne change jamais dans la branche de conflit ;
|
||||
- Backfill conserve explicitement la distinction conflit / observation idempotente ;
|
||||
- le Worker doit continuer à traiter les identités suivantes après une quarantaine ;
|
||||
- le lifecycle final est séparé en `pre.008`, `pre.009`, `pre.010`, puis `rel.001` conformément aux règles actuelles.
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
Aucune question fonctionnelle bloquante pour `0.3.16`.
|
||||
|
||||
Le test PostgreSQL live reste conditionné à la disponibilité d'un PostgreSQL isolé ; son absence n'autorise pas à prétendre qu'il a été exécuté.
|
||||
|
||||
## Suite
|
||||
|
||||
Après gate technique propre : `0.3.16-pre.009` — réconciliation documentaire finale de `0.3.16`, sans nouveau comportement runtime.
|
||||
Reference in New Issue
Block a user