v0.3.11-pre.007
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/032-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION_PLAN.md -->
|
||||
<!-- version: 6 -->
|
||||
<!-- version: 7 -->
|
||||
|
||||
# Plan v0.3.11 — fondation runtime du Worker RawTransaction ingest
|
||||
|
||||
@@ -726,12 +726,14 @@ Budget cible : **15–20 min**. Introduire le supervisor, les JoinSet/joins priv
|
||||
|
||||
Budget cible : **15–20 min**. `mpsc` borné, backpressure, ingress privé, common `RawTransactionMaterial -> RawTransaction`, observation-key domain/golden et assembly. Pas de source réseau.
|
||||
|
||||
État après matérialisation : **implémenté, gate opérateur requis**. Le supervisor possède un channel central `tokio::sync::mpsc` borné par `admission_queue_capacity`. Le seam source reçoit directement un clone du sender borné ainsi que le `watch<bool>` de stop ; le harness prouve `send().await` sous saturation et un `select! biased` stop-before-send, sans helper de production mort avant les vraies sources. L'ingress reste crate-private et transporte material source-neutral, network attendu, provenance sûre et une source key opaque de 32 bytes. Le Worker canonicalise exclusivement via `ksp-raw-transaction-lib`, vérifie le réseau avant/après canonicalisation, dérive l'observation key sous `ksp.raw_transaction_ingest.observation.v1` à partir de `(network, signature, source_key)`, puis assemble un `RawTransactionAcquisition` via le common RAW. Au stop, le receiver ferme les nouvelles admissions puis canonicalise les entrées déjà admises avant le join final. Aucune persistence Store, source live, Transport, snapshot concret ou policy provider n'est introduite.
|
||||
État après matérialisation : **implémenté et gate opérateur validé après `pre.006-fix.001`**. Le supervisor possède un channel central `tokio::sync::mpsc` borné par `admission_queue_capacity`. Le seam source reçoit directement un clone du sender borné ainsi que le `watch<bool>` de stop ; le harness prouve `send().await` sous saturation et un `select! biased` stop-before-send, sans helper de production mort avant les vraies sources. L'ingress reste crate-private et transporte material source-neutral, network attendu, provenance sûre et une source key opaque de 32 bytes. Le Worker canonicalise exclusivement via `ksp-raw-transaction-lib`, vérifie le réseau avant/après canonicalisation, dérive l'observation key sous `ksp.raw_transaction_ingest.observation.v1` à partir de `(network, signature, source_key)`, puis assemble un `RawTransactionAcquisition` via le common RAW. `pre.006-fix.001` corrige uniquement les séparateurs de branches du `tokio::select!` de test ; le gate communiqué le 8 septembre 2026 est ensuite vert sur `fmt`, audits, `check`, Clippy strict, 22 tests de crate et doc-tests. Aucun arbre Cargo n'a été rejoué après ce fix strictement sans changement de dépendance. Aucune persistence Store, source live, Transport, snapshot concret ou policy provider n'est introduite.
|
||||
|
||||
### `pre.007` — persistence Store + idempotence/conflict
|
||||
|
||||
Budget cible : **15–20 min**. Port privé Store, mode Normal, concurrency bornée, outcomes new/idempotent/purged, observation distincte, Store error et content conflict terminal.
|
||||
|
||||
État après matérialisation : **implémenté, gate opérateur requis**. La crate possède désormais un port de persistence Store crate-private, implémenté par la façade `ksp-store-lib::Store`, et appelle exclusivement l'opération atomique transaction + observation en `RawTransactionAcquisitionMode::Normal`. Le supervisor possède un `JoinSet` privé de persistences ; il ne lit une nouvelle acquisition que si `in_flight < persistence_concurrency`, ce qui borne les écritures sans sémaphore ni file secondaire. Les succès distinguent `Inserted`, `AlreadyPresent`, `SkippedPurged` et les observations `Inserted`, `AlreadyPresent`, `NotRecorded`; `Rehydrated` ou toute combinaison impossible en mode Normal deviennent `runtime_invalid`. `store_api.raw_conflict` est réduit à `worker_raw_transaction_ingest.content_conflict`; toute autre erreur Store devient `worker_raw_transaction_ingest.store_failed` en ne conservant que le `ErrorCode` inférieur sûr. Le premier fault de cette tranche signale le stop privé, ferme ensuite les nouvelles admissions, draine les acquisitions déjà admises, rejoint persistences et sources, puis publie le terminal. Les races terminales fortes et le timeout/abort restent réservés à `pre.009`; les compteurs/snapshots restent réservés à `pre.008`.
|
||||
|
||||
### `pre.008` — snapshots concrets + projection Worker API
|
||||
|
||||
Budget cible : **15–20 min**. `watch` latest-value, compteurs checked, common projection, slow/no listener et terminal retained.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/028-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION.md -->
|
||||
<!-- version: 9 -->
|
||||
<!-- version: 10 -->
|
||||
|
||||
# Validation v0.3.11 — fondation runtime du Worker RawTransaction ingest
|
||||
|
||||
@@ -1014,3 +1014,162 @@ cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features
|
||||
|
||||
Critère de passage : admission bornée/backpressure, stop-preemption, canonicalisation common, golden observation et assembly sont verts ; aucune persistence Store, source live, Transport ou snapshot concret n'apparaît.
|
||||
|
||||
## 18. Fermeture opérateur `pre.006-fix.001` et matérialisation `pre.007`
|
||||
|
||||
### 18.1 Fermeture opérateur de `pre.006-fix.001`
|
||||
|
||||
Le journal opérateur communiqué le 8 septembre 2026 ferme `0.3.11-pre.006-fix.001` (`workspace.package.version = 0.3.11-pre.6.fix.1`) :
|
||||
|
||||
```text
|
||||
cargo fmt --all : terminé sans erreur
|
||||
python3 scripts/audit_rust_workspace_rules.py : clean, export completeness 0
|
||||
python3 scripts/audit_markdown_tables.py ... : clean (340 tables, 782 files)
|
||||
cargo check --workspace : terminé sans erreur
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings : terminé sans erreur
|
||||
cargo test -p ksp-worker-raw-transaction-ingest-lib : 15 unit + 3 dependency-boundary + 4 public API PASS, 0 échec
|
||||
doc-tests : PASS
|
||||
```
|
||||
|
||||
Aucun `cargo tree` n'a été rejoué après ce fix. Ce choix ne laisse pas de gap de dépendance : `pre.006-fix.001` modifie uniquement `Cargo.toml` pour le numéro de version, un test Rust et son delta ; aucune dépendance ni feature n'est ajoutée, retirée ou modifiée.
|
||||
|
||||
`pre.007` peut donc être ouverte.
|
||||
|
||||
### 18.2 Port Store privé et mode Normal
|
||||
|
||||
`pre.007` ajoute `RawTransactionIngestPersistencePort`, strictement crate-private. Son implémentation productive vise uniquement `ksp_store_lib::Store` et délègue à :
|
||||
|
||||
```text
|
||||
RawTransactionWrite::persist_raw_transaction_acquisition(..., RawTransactionAcquisitionMode::Normal)
|
||||
```
|
||||
|
||||
Le port ne connaît aucun backend concret. Il vérifie le network avant write et l'alignement exact entre transaction et observation. Le Store reste source de vérité ; aucun cache de déduplication mémoire n'est ajouté.
|
||||
|
||||
### 18.3 Classification entity + observation
|
||||
|
||||
Les succès Store admis en mode Normal sont classifiés exactement :
|
||||
|
||||
```text
|
||||
Inserted + Inserted -> entity Inserted / observation Inserted
|
||||
AlreadyPresent + Inserted -> entity AlreadyPresent / observation Inserted
|
||||
AlreadyPresent + AlreadyPresent -> entity AlreadyPresent / observation AlreadyPresent
|
||||
SkippedPurged + NotRecorded -> entity SkippedPurged / observation NotRecorded
|
||||
```
|
||||
|
||||
`Rehydrated` est interdit en mode Normal. Toute combinaison non définie ci-dessus devient `worker_raw_transaction_ingest.runtime_invalid` et n'est jamais traitée comme un succès silencieux.
|
||||
|
||||
### 18.4 Content conflict et Store failure
|
||||
|
||||
Deux ErrorCode publics sont ouverts parce qu'ils deviennent réellement observables dans cette tranche :
|
||||
|
||||
```text
|
||||
worker_raw_transaction_ingest.content_conflict
|
||||
worker_raw_transaction_ingest.store_failed
|
||||
```
|
||||
|
||||
Mapping :
|
||||
|
||||
```text
|
||||
ksp_store_lib::ERROR_CODE_RAW_CONFLICT -> content_conflict
|
||||
autre erreur Store -> store_failed
|
||||
```
|
||||
|
||||
Pour `store_failed`, le Worker ne conserve que `store_domain` et `store_code`, issus du `ErrorCode` inférieur déjà sûr. Le message/source arbitraire Store n'est pas copié dans l'erreur Worker, le handle ou le terminal.
|
||||
|
||||
### 18.5 Concurrence bornée de persistence
|
||||
|
||||
Le supervisor possède un `JoinSet` privé de futures de persistence. Il n'exécute la branche admission que lorsque :
|
||||
|
||||
```text
|
||||
persistence.len() < settings.persistence_concurrency()
|
||||
```
|
||||
|
||||
Il n'existe ni sémaphore supplémentaire, ni queue de persistence non bornée. Sous saturation de persistence, le supervisor attend une complétion Store avant de retirer une nouvelle acquisition de la queue centrale ; la backpressure remonte ainsi jusqu'au `mpsc` borné.
|
||||
|
||||
Le harness avec `persistence_concurrency = 2` bloque volontairement les écritures Store et prouve que `max_active == 2` avec quatre acquisitions admises.
|
||||
|
||||
### 18.6 Drain et terminal de `pre.007`
|
||||
|
||||
Lors d'un stop normal, d'un content conflict ou d'une erreur Store :
|
||||
|
||||
```text
|
||||
signaler le stop privé aux sources si fault
|
||||
fermer les nouvelles admissions
|
||||
canonicaliser/persister les acquisitions déjà admises
|
||||
attendre toutes les persistences en vol
|
||||
attendre toutes les tâches source
|
||||
publier Stopped ou le premier Faulted retenu
|
||||
```
|
||||
|
||||
Cette tranche ne fige pas encore la priorité complète des courses stop/fault et n'introduit aucun timeout/abort ; ces responsabilités restent dans `pre.009`.
|
||||
|
||||
### 18.7 Preuves ajoutées
|
||||
|
||||
Les tests `pre.007` couvrent :
|
||||
|
||||
```text
|
||||
mode Store exactement Normal
|
||||
Inserted / AlreadyPresent / SkippedPurged
|
||||
observation Inserted / AlreadyPresent / NotRecorded
|
||||
Rehydrated et couples impossibles -> runtime_invalid
|
||||
network mismatch avant write
|
||||
content conflict -> ErrorCode Worker terminal dédié
|
||||
Store failure -> ErrorCode Worker dédié sans texte distant
|
||||
persistence_concurrency réellement bornée à 2
|
||||
content conflict runtime -> terminal Faulted(content_conflict)
|
||||
Store failure runtime -> terminal Faulted(store_failed)
|
||||
public API -> deux ErrorCode stables depuis crate-root
|
||||
dependency boundary -> persistence privée requise, backend/Transport/snapshot interdits
|
||||
```
|
||||
|
||||
### 18.8 Frontière volontaire de `pre.007`
|
||||
|
||||
La tranche n'introduit toujours aucun :
|
||||
|
||||
```text
|
||||
backend Store direct
|
||||
ForceRehydrate
|
||||
source live
|
||||
Transport
|
||||
Config
|
||||
snapshot concret / compteurs publics
|
||||
source_failed
|
||||
counter_exhausted
|
||||
drain_timeout / abort forcé
|
||||
retry / reconnect / gap repair
|
||||
```
|
||||
|
||||
`pre.008` reste propriétaire des snapshots/counters. `pre.009` reste propriétaire du hardening shutdown, du timeout/abort et des courses fault/stop.
|
||||
|
||||
### 18.9 Preuves locales d'assemblage `pre.007`
|
||||
|
||||
Exécuté 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
|
||||
Markdown table audit: clean
|
||||
|
||||
scan production : aucun unwrap, expect, panic, unbounded_channel
|
||||
scan scope : aucun ksp-store-postgres-lib, aucun Transport, aucun snapshot concret
|
||||
```
|
||||
|
||||
L'environnement d'assemblage ne fournit ni `cargo`, ni `rustc`, ni `rustfmt`. Aucun gate Cargo de `pre.007` n'est déclaré PASS localement.
|
||||
|
||||
### 18.10 Gate opérateur demandé pour `pre.007`
|
||||
|
||||
Aucune dépendance ni feature n'étant modifiée par `pre.007`, aucun `cargo tree` intermédiaire n'est requis. Le gate demandé est :
|
||||
|
||||
```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
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
cargo test -p ksp-worker-raw-transaction-ingest-lib
|
||||
```
|
||||
|
||||
Critère de passage : persistence Normal, outcomes/idempotence/purge, concurrence bornée et terminaux conflict/Store sont verts, sans backend direct, Transport ni snapshot concret.
|
||||
|
||||
Reference in New Issue
Block a user