v0.3.4-pre.005

This commit is contained in:
2026-08-30 22:17:47 +02:00
parent eb6dbc31e8
commit 50d4142797
10 changed files with 766 additions and 31 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md -->
<!-- version: 8 -->
<!-- version: 9 -->
# Plan `0.3.4` — Store/PostgreSQL `RawAccountState` + complétude RAW
@@ -617,17 +617,21 @@ La tranche reste strictement read-only : aucun `INSERT`, `UPDATE`, `DELETE`, `ON
#### `pre.004-fix.001` — conformité Clippy du mapping `Row`
**Statut : réalisé ; gate opérateur complet à rejouer.**
**Statut : réalisé ; gate opérateur complet PASS.**
Le gate opérateur de `pre.004` confirme `cargo check --workspace`, les suites ciblées `ksp-store-api`, `ksp-store-lib`, `ksp-store-postgres-lib` (52 tests), `ksp-config-lib` et `ksp-store-lib --no-default-features`, tandis que `cargo clippy --workspace --all-targets` rejette les 27 extractions `Row::try_get(...).map_err(...)?` du nouveau module. Chaque occurrence produit conjointement `clippy::question-mark-used` et `clippy::implicit-return`, conformément aux interdictions `RUST-ERR-002/003`. Le même gate signale aussi un `crate_root` inutilisé dans le canari `pre_003_v002_schema_is_complete_without_account_trait_or_write_dispatch`.
Le correctif déplie les extractions physiques en `match` typés avec retour `DataInvalid` explicite et supprime uniquement la variable de test inutilisée. Aucun SELECT, phase d'erreur, type physique, invariant de mapping, signature de bridge, test fonctionnel, migration ou checksum n'est modifié. La version Cargo devient `0.3.4-pre.4.fix.1` conformément à `VER-ID-007/010`, car deux fichiers Rust sont modifiés.
Le correctif déplie les extractions physiques en `match` typés avec retour `DataInvalid` explicite et supprime uniquement la variable de test inutilisée. Aucun SELECT, phase d'erreur, type physique, invariant de mapping, signature de bridge, test fonctionnel, migration ou checksum n'est modifié. La version Cargo devient `0.3.4-pre.4.fix.1` conformément à `VER-ID-007/010`, car deux fichiers Rust sont modifiés. Le gate opérateur complet du correctif est vert : audits Rust/Markdown, workspace check, Clippy all-targets, suites Store API/façade/PostgreSQL/Config et `--no-default-features` passent.
### `pre.005` — Acquisition atomique et idempotence
**Statut : planifié.**
**Statut : réalisé ; gate opérateur complet à rejouer.**
Budget cible : **15-20 min**. Implémenter l'acquisition atomique state+observation, l'idempotence exacte et la classification des conflits.
Budget cible : **15-20 min**. L'acquisition account est désormais une transaction PostgreSQL unique : guard réseau et identité exacte avant I/O, `INSERT ... ON CONFLICT DO NOTHING` du state, verrouillage `FOR UPDATE` et comparaison exacte de `lamports/owner/executable/rent_epoch/data` en cas de collision, puis insertion idempotente de l'observation avec comparaison exacte de la référence, de toute la provenance et des metadata optionnelles. Une divergence retourne `Conflict` sans overwrite.
Si le state vient d'être inséré mais que l'observation collide avec un contenu divergent, le retour d'erreur abandonne la transaction et ne laisse donc aucun state orphelin durable. Le bridge étroit `PostgresBackend::persist_raw_account_acquisition` est ouvert sans implémenter `RawAccountStateWrite`; les quatre traits account restent fermés jusqu'à `pre.008`.
`record_raw_account_observation`, `list_raw_account_states`, le cursor `KSPA`, tout `UPDATE`/`DELETE` account et tout `ON CONFLICT DO UPDATE` restent absents. `pre.006` conserve la responsabilité de l'observation supplémentaire et des scénarios de concurrence/cancellation ciblés.
### `pre.006` — Observation supplémentaire et concurrence unitaire

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md -->
<!-- version: 7 -->
<!-- version: 8 -->
# Validation `0.3.4` — Store/PostgreSQL `RawAccountState` + complétude RAW
@@ -274,8 +274,8 @@ Le test live account devra être opt-in/ignored, URI stdin, sans environnement n
| pre.001 | audit, kbot3, threat model, V002 design, sizing, plan/validation | DONE |
| pre.002 | V002 registry + deux tables + PK/FK de base, sans repository | PASS |
| pre.003 | contraintes complètes, index, schema compatibility, checksum V002 | PASS |
| pre.004 | mapping privé state/observation + get reads + hostile rows | RECHECK |
| pre.005 | acquisition atomique state+observation + idempotence/conflict | PLANNED |
| pre.004 | mapping privé state/observation + get reads + hostile rows | PASS |
| pre.005 | acquisition atomique state+observation + idempotence/conflict | RECHECK |
| pre.006 | observation supplémentaire + races/cancellation unitaires | PLANNED |
| pre.007 | list RawAccountStateQuery + keyset cursor V1 account | PLANNED |
| pre.008 | 4 impl backend + 4 dispatch Store + conformance 10/10 | PLANNED |
@@ -399,7 +399,7 @@ Gate opérateur de `pre.003-fix.001` du 2026-08-30 : **PASS complet** — audits
## 21. Verdict `pre.004`
Mapping PostgreSQL privé account : **tests opérateur PASS ; Clippy `pre.004` FAIL ; `pre.004-fix.001` appliqué statiquement, gate complet à rejouer**.
Mapping PostgreSQL privé account : **PASS final via `pre.004-fix.001`**. Le gate initial `pre.004` avait échoué uniquement sur Clippy ; le gate complet du correctif est désormais vert.
Surface matérialisée :
@@ -447,5 +447,32 @@ Invariants du fix :
- aucun write, cursor, trait account ou dispatch Store ouvert ;
- `workspace.package.version = 0.3.4-pre.4.fix.1`.
Validations exécutées dans l'environnement d'assemblage du fix : audit Rust général/export/workspace **PASS**, audit Markdown **PASS**, absence de `?` dans `src/raw_account.rs` confirmée. Le gate opérateur complet doit rejouer `cargo fmt`, audits, check, Clippy et suites ciblées après application du delta.
Validations exécutées dans l'environnement d'assemblage du fix : audit Rust général/export/workspace **PASS**, audit Markdown **PASS**, absence de `?` dans `src/raw_account.rs` confirmée. Gate opérateur du 2026-08-30 : **PASS complet** — audits Rust/Markdown, workspace check, Clippy all-targets, Store API, Store façade, backend PostgreSQL (52 tests), Config et `--no-default-features` sont verts.
## 22. Verdict `pre.005`
Acquisition atomique account : **PASS statique ; gate opérateur complet à rejouer**.
Surface ajoutée :
```text
PostgresBackend::persist_raw_account_acquisition
INSERT state ON CONFLICT DO NOTHING
SELECT state FOR UPDATE sur collision
comparaison exacte du state canonique complet
INSERT observation ON CONFLICT DO NOTHING
SELECT observation FOR UPDATE sur collision
comparaison exacte référence + provenance + metadata optionnelles
COMMIT unique state + observation
```
Les préconditions `state.reference.network == backend.network`, `observation.account.network == backend.network` et `observation.account == state.reference` sont évaluées avant `pool.get()`. Une divergence de référence ou de contenu est classée `Conflict`; un échec physique d'écriture reste `WriteFailed`, sans texte PostgreSQL conservé.
L'idempotence state ne fait aucune confiance exclusive à `state_hash` : un même `(pubkey, slot, state_hash)` n'est `AlreadyPresent` que si `lamports`, `owner`, `executable`, `rent_epoch` et `data` sont identiques. L'idempotence observation compare le modèle `RawAccountObservation` complet, y compris `is_startup`, `transaction_signature`, `write_version` et toute la provenance.
La transaction commune garantit qu'une collision divergente sur l'observation après insertion d'un nouveau state ne peut pas laisser ce state durable isolément. Aucun `has_*`, `ON CONFLICT DO UPDATE`, `UPDATE` ou `DELETE` account n'est introduit.
Canaries `pre.005` : guard réseau/référence, comparaison state complète, comparaison observation complète, encodage origin fermé, SQL `DO NOTHING + FOR UPDATE`, bridge backend-agnostic et absence des quatre implémentations `RawAccount*`.
Reste explicitement hors tranche : `record_raw_account_observation` (`pre.006`), concurrence/cancellation ciblées (`pre.006`), pagination/cursor (`pre.007`) et implémentations/dispatch 10/10 (`pre.008`). Les migrations V000/V001/V002 restent inchangées et le checksum V002 final demeure `ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e`.