v0.3.4-pre.005
This commit is contained in:
308
deltas/0.3.4/pre.005.md
Normal file
308
deltas/0.3.4/pre.005.md
Normal file
@@ -0,0 +1,308 @@
|
||||
<!-- file: deltas/0.3.4/pre.005.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.4-pre.005` — acquisition atomique et idempotence `RawAccountState`
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
```text
|
||||
0.3.4-pre.4.fix.1
|
||||
```
|
||||
|
||||
Le gate opérateur fourni le 2026-08-30 pour `pre.004-fix.001` est entièrement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 239 tables / 141 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 — 52 unit tests + canaris, live ignored
|
||||
cargo test -p ksp-config-lib PASS — 128 unit tests + ownership/public API
|
||||
cargo check -p ksp-store-lib --no-default-features PASS
|
||||
```
|
||||
|
||||
Le mapping/read account de `pre.004` est donc considéré acquis avant l'ouverture des writes d'acquisition.
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Implémenter uniquement l'écriture atomique du couple :
|
||||
|
||||
```text
|
||||
RawAccountState
|
||||
+
|
||||
RawAccountObservation
|
||||
```
|
||||
|
||||
avec les invariants figés par `pre.001` :
|
||||
|
||||
```text
|
||||
guards réseau/référence avant I/O
|
||||
state insert idempotent
|
||||
collision state -> FOR UPDATE + comparaison exacte
|
||||
observation insert idempotente
|
||||
collision observation -> FOR UPDATE + comparaison exacte
|
||||
commit unique
|
||||
aucun overwrite silencieux
|
||||
```
|
||||
|
||||
L'observation supplémentaire sans retransmettre les bytes account reste réservée à `pre.006`.
|
||||
|
||||
## 3. Version
|
||||
|
||||
Le workspace passe à :
|
||||
|
||||
```text
|
||||
0.3.4-pre.5
|
||||
```
|
||||
|
||||
Aucune crate ne redéfinit localement la version héritée.
|
||||
|
||||
## 4. Préconditions avant I/O
|
||||
|
||||
`persist_raw_account_acquisition` valide avant `pool.get()` :
|
||||
|
||||
```text
|
||||
state.reference.network == backend.network
|
||||
observation.account.network == backend.network
|
||||
observation.account == state.reference
|
||||
```
|
||||
|
||||
Un mauvais réseau devient `WrongNetwork`. Une référence observation/state divergente devient `Conflict`. Aucune connexion PostgreSQL n'est consommée avant ces gardes.
|
||||
|
||||
## 5. Insertion canonique du state
|
||||
|
||||
Le state utilise :
|
||||
|
||||
```text
|
||||
INSERT INTO ksp_raw_account_states (...)
|
||||
ON CONFLICT (pubkey, slot, state_hash) DO NOTHING
|
||||
RETURNING pubkey
|
||||
```
|
||||
|
||||
Les domaines `u64` restent encodés sans narrowing via chaînes décimales et cast PostgreSQL `TEXT::NUMERIC` :
|
||||
|
||||
```text
|
||||
slot
|
||||
lamports
|
||||
rent_epoch
|
||||
```
|
||||
|
||||
Les pubkeys/hash restent en bytes fixes et `data` est persistée sans base64 ni copie structurale.
|
||||
|
||||
Si l'INSERT gagne :
|
||||
|
||||
```text
|
||||
RawEntityWriteOutcome::Inserted
|
||||
```
|
||||
|
||||
Si l'identité existe déjà, le backend charge la ligne canonique sous :
|
||||
|
||||
```text
|
||||
FOR UPDATE
|
||||
```
|
||||
|
||||
et compare exactement :
|
||||
|
||||
```text
|
||||
reference
|
||||
lamports
|
||||
owner
|
||||
executable
|
||||
rent_epoch
|
||||
data
|
||||
```
|
||||
|
||||
Le `state_hash` ne suffit donc jamais à déclarer l'idempotence. Contenu identique -> `AlreadyPresent`; contenu divergent -> `Conflict`.
|
||||
|
||||
## 6. Insertion idempotente de l'observation
|
||||
|
||||
L'observation est encodée avec toute la provenance et toutes les metadata optionnelles :
|
||||
|
||||
```text
|
||||
observation_key
|
||||
account pubkey/slot/state_hash
|
||||
provider
|
||||
protocol
|
||||
acquisition_method
|
||||
origin
|
||||
received_at
|
||||
capture_session_id
|
||||
commitment
|
||||
endpoint_id
|
||||
filter_id
|
||||
observed_at
|
||||
source_payload_hash
|
||||
source_payload_size_bytes
|
||||
is_startup
|
||||
transaction_signature
|
||||
write_version
|
||||
```
|
||||
|
||||
Le SQL utilise :
|
||||
|
||||
```text
|
||||
ON CONFLICT (observation_key) DO NOTHING
|
||||
```
|
||||
|
||||
En cas de collision, la ligne existante est relue `FOR UPDATE`, décodée avec le codec hostile-row de `pre.004`, puis comparée au `RawAccountObservation` entrant complet. Identique -> `AlreadyPresent`; divergent -> `Conflict`.
|
||||
|
||||
Aucun champ optionnel n'est ignoré dans l'idempotence.
|
||||
|
||||
## 7. Atomicité
|
||||
|
||||
State et observation vivent dans la même transaction PostgreSQL :
|
||||
|
||||
```text
|
||||
BEGIN
|
||||
state insert/compare
|
||||
observation insert/compare
|
||||
COMMIT
|
||||
```
|
||||
|
||||
Si un nouveau state a été inséré mais que l'observation collide avec un contenu divergent, le chemin retourne une erreur avant commit. Le drop de la transaction annule alors l'insertion du state : aucune moitié d'acquisition durable n'est admise.
|
||||
|
||||
Aucun pré-check `has_*`, aucun `ON CONFLICT DO UPDATE`, aucun `UPDATE` et aucun `DELETE` account n'est introduit.
|
||||
|
||||
## 8. Surface backend
|
||||
|
||||
`PostgresBackend` expose le bridge étroit :
|
||||
|
||||
```text
|
||||
persist_raw_account_acquisition(
|
||||
RawAccountState,
|
||||
RawAccountObservation,
|
||||
) -> RawAcquisitionWriteOutcome
|
||||
```
|
||||
|
||||
Le bridge reste backend-agnostic et n'expose aucun type PostgreSQL.
|
||||
|
||||
Cette méthode n'implémente pas encore `RawAccountStateWrite`. Les quatre traits account restent volontairement absents jusqu'à `pre.008` afin d'ouvrir la conformance physique 10/10 en une seule tranche.
|
||||
|
||||
## 9. Tests et canaries
|
||||
|
||||
Les tests unitaires ajoutés couvrent :
|
||||
|
||||
```text
|
||||
guard réseau state
|
||||
référence observation/state exacte
|
||||
state identique -> comparaison vraie
|
||||
même référence/hash + lamports divergent -> comparaison fausse
|
||||
observation identique -> égalité exacte
|
||||
même clé/référence + write_version divergent -> non-identique
|
||||
encodage exact des cinq RawAcquisitionOrigin
|
||||
```
|
||||
|
||||
Le canari `dependency_boundary` exige maintenant :
|
||||
|
||||
```text
|
||||
INSERT_ACCOUNT_STATE_SQL
|
||||
INSERT_ACCOUNT_OBSERVATION_SQL
|
||||
LOCK_ACCOUNT_STATE_SQL
|
||||
LOCK_ACCOUNT_OBSERVATION_SQL
|
||||
ON CONFLICT ... DO NOTHING
|
||||
FOR UPDATE
|
||||
persist_raw_account_acquisition
|
||||
```
|
||||
|
||||
et continue d'interdire :
|
||||
|
||||
```text
|
||||
UPDATE / DELETE account
|
||||
ON CONFLICT DO UPDATE
|
||||
record_raw_account_observation
|
||||
list_raw_account_states
|
||||
OFFSET
|
||||
les quatre impl RawAccount*
|
||||
```
|
||||
|
||||
`public_api.rs` vérifie le nouveau bridge backend-agnostic.
|
||||
|
||||
## 10. Scope explicitement reporté
|
||||
|
||||
```text
|
||||
record_raw_account_observation pre.006
|
||||
races/cancellation ciblées pre.006
|
||||
list_raw_account_states pre.007
|
||||
cursor KSPA pre.007
|
||||
4 impl RawAccount* PostgresBackend pre.008
|
||||
4 dispatch Store pre.008
|
||||
live PostgreSQL account pre.009
|
||||
```
|
||||
|
||||
## 11. Migrations
|
||||
|
||||
Aucune ressource sous `migrations/` n'est modifiée.
|
||||
|
||||
Checksums conservés :
|
||||
|
||||
```text
|
||||
V000 = d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450
|
||||
V001 = 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51
|
||||
V002 = ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e
|
||||
```
|
||||
|
||||
## 12. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-store-postgres-lib/src/lib.rs
|
||||
crates/ksp-store-postgres-lib/src/raw_account.rs
|
||||
crates/ksp-store-postgres-lib/src/runtime.rs
|
||||
crates/ksp-store-postgres-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-store-postgres-lib/tests/public_api.rs
|
||||
crates/ksp-store-postgres-lib/unit_tests/raw_account.rs
|
||||
docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md
|
||||
docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md
|
||||
```
|
||||
|
||||
## 13. Fichier ajouté
|
||||
|
||||
```text
|
||||
deltas/0.3.4/pre.005.md
|
||||
```
|
||||
|
||||
## 14. Fichiers supprimés
|
||||
|
||||
```text
|
||||
aucun
|
||||
```
|
||||
|
||||
## 15. Validations exécutées dans l'environnement d'assemblage
|
||||
|
||||
```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.4
|
||||
PASS
|
||||
```
|
||||
|
||||
Les contrôles différentiels doivent également confirmer l'identité byte-à-byte de V000/V001/V002 et l'absence de surface `pre.006+`.
|
||||
|
||||
## 16. Validations non exécutées dans l'environnement d'assemblage
|
||||
|
||||
`cargo`, `rustc` et `rustfmt` ne sont pas disponibles dans l'environnement d'assemblage. Aucun résultat Cargo post-`pre.005` n'est revendiqué ici.
|
||||
|
||||
Gate opérateur à rejouer :
|
||||
|
||||
```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.4
|
||||
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
|
||||
```
|
||||
|
||||
## 17. Verdict
|
||||
|
||||
`pre.005` ouvre uniquement l'acquisition atomique `RawAccountState + RawAccountObservation`. L'observation supplémentaire, les races/cancellations dédiées, la pagination et les capabilities account restent fermées conformément au sizing souple de `0.3.4`.
|
||||
Reference in New Issue
Block a user