Files
2026-08-30 22:17:47 +02:00

8.2 KiB

Delta 0.3.4-pre.005 — acquisition atomique et idempotence RawAccountState

1. Base requise

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 :

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 :

RawAccountState
+
RawAccountObservation

avec les invariants figés par pre.001 :

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 à :

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() :

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 :

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 :

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 :

RawEntityWriteOutcome::Inserted

Si l'identité existe déjà, le backend charge la ligne canonique sous :

FOR UPDATE

et compare exactement :

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 :

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 :

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 :

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 :

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 :

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 :

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 :

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é

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 :

V000 = d29068b8c13b9dc0cc9ef6aaadd0fa12d41e0fe4c56541a1118c4bfc846a1450
V001 = 31488cda2f08f3f46c4cdbdbb6c18c243662fada02eac4487040c8735d72cc51
V002 = ff21605ed45f7ab4c0f92bbb692700b4118a9488b04d50a31d259ac59bdb550e

12. Fichiers modifiés

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é

deltas/0.3.4/pre.005.md

14. Fichiers supprimés

aucun

15. Validations exécutées dans l'environnement d'assemblage

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 :

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.