v0.3.11-pre.006

This commit is contained in:
2026-09-08 10:54:40 +02:00
parent 0db32a865c
commit 61d8b1dee2
10 changed files with 769 additions and 37 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/032-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION_PLAN.md -->
<!-- version: 5 -->
<!-- version: 6 -->
# Plan v0.3.11 — fondation runtime du Worker RawTransaction ingest
@@ -344,7 +344,7 @@ Les `JoinHandle`/`JoinSet` restent strictement privés. Dropper le handle public
Un seul channel central :
```text
tokio::sync::mpsc::channel<PrivateRawTransactionIngress>(admission_queue_capacity)
tokio::sync::mpsc::channel<RawTransactionIngress>(admission_queue_capacity)
```
Le channel est borné. `send().await` applique le backpressure ; aucun `unbounded_channel`, aucun drop silencieux et aucune event queue publique ne sont admis.
@@ -361,13 +361,14 @@ Un `watch<RawTransactionIngestSnapshot>` privé conserve uniquement la dernière
## 9. Seam/harness déterministe sans réseau
Le runtime de fondation est prouvé par un harness privé qui produit des `PrivateRawTransactionIngress` contrôlés.
Le runtime de fondation est prouvé par un harness privé qui produit des `RawTransactionIngress` crate-private contrôlés.
Une entrée de harness contient conceptuellement :
```text
RawTransactionMaterial
RawObservationKey déterministe Worker-owned
RawNetworkId attendu
source key privée déterministe [u8; 32]
RawAcquisitionProvenance sûre
```
@@ -413,9 +414,9 @@ La Worker observation key est un SHA-256 KSP-owned versionné et domain-separate
ksp.raw_transaction_ingest.observation.v1
```
Les bytes exacts/golden seront figés avec le premier code de persistence, à partir d'éléments stables fournis par la source technique et de l'identité `(network, signature)`. Aucun timestamp local aléatoire ni run id ne peut rendre une rediffusion identique non idempotente.
Les bytes exacts/golden sont figés en `pre.006` à partir de l'identité `(network, signature)` et d'une source key privée opaque de 32 bytes. Le SHA-256 est domain-separated puis encode chaque composant avec une longueur `u64` big-endian. Aucun timestamp local aléatoire, run id ni ordre d'admission ne peut rendre une rediffusion identique non idempotente.
Les éléments source exacts ne sont pas figés publiquement avant `0.3.12`; le harness utilise une source key privée déterministe afin de prouver l'idempotence du domaine Worker.
Les éléments provider/source utilisés pour produire cette source key ne sont pas figés publiquement avant `0.3.12`; le harness utilise une source key privée déterministe afin de prouver l'idempotence du domaine Worker sans ouvrir une API source prématurée.
### 10.3 Outcomes
@@ -719,12 +720,14 @@ Les méthodes `snapshot_source()` et `worker_snapshot_source()` prévues par la
Budget cible : **1520 min**. Introduire le supervisor, les JoinSet/joins privés, intégrer le wake-up de stop déjà matérialisé à l'ownership des tâches enfants, ajouter le test source seam et prouver qu'aucune tâche enfant ne survit au terminal. Pas encore de persistence réelle.
État après matérialisation : **implémenté, gate opérateur requis**. Le task racine est désormais le supervisor privé et possède un `tokio::task::JoinSet<()>`. Un seam privé de spawn de sources reçoit le `JoinSet` et un clone du `watch<bool>` de stop ; la production utilise un seam vide tandis que les unit tests injectent des tâches coopératives déterministes. Le supervisor récole les enfants terminés pendant l'exécution puis, au stop ou à la fermeture du channel de contrôle, attend la fin de tous les enfants avant de publier `Stopped`. Un `JoinError` observé marque la supervision comme non clean ; si la fermeture de supervision est ensuite engagée, le terminal est projeté vers `Faulted(worker_raw_transaction_ingest.runtime_invalid)`. Le traitement immédiat/prioritaire des faults reste différé à `pre.009`. Aucun timeout/abort forcé n'est encore introduit : ce hardening reste réservé à `pre.009`.
État après matérialisation : **implémenté et gate opérateur validé**. Le task racine est désormais le supervisor privé et possède un `tokio::task::JoinSet<()>`. Un seam privé de spawn de sources reçoit le `JoinSet` et un clone du `watch<bool>` de stop ; la production utilise un seam vide tandis que les unit tests injectent des tâches coopératives déterministes. Le supervisor récole les enfants terminés pendant l'exécution puis, au stop ou à la fermeture du channel de contrôle, attend la fin de tous les enfants avant de publier `Stopped`. Un `JoinError` observé marque la supervision comme non clean ; si la fermeture de supervision est ensuite engagée, le terminal est projeté vers `Faulted(worker_raw_transaction_ingest.runtime_invalid)`. Le traitement immédiat/prioritaire des faults reste différé à `pre.009`. Aucun timeout/abort forcé n'est encore introduit : ce hardening reste réservé à `pre.009`. Le gate communiqué le 8 septembre 2026 est vert sur `fmt`, audits, `check`, Clippy strict, 18 tests de crate, doc-tests et les deux arbres Cargo.
### `pre.006` — admission bornée + canonicalisation common
Budget cible : **1520 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.
### `pre.007` — persistence Store + idempotence/conflict
Budget cible : **1520 min**. Port privé Store, mode Normal, concurrency bornée, outcomes new/idempotent/purged, observation distincte, Store error et content conflict terminal.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/028-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION.md -->
<!-- version: 8 -->
<!-- version: 9 -->
# Validation v0.3.11 — fondation runtime du Worker RawTransaction ingest
@@ -852,3 +852,165 @@ cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features
Critère de passage : le supervisor/JoinSet privé, le seam source déterministe et le join complet avant terminal sont verts ; aucun `mpsc`, common RAW assembly, Store write, snapshot concret, source live ou Transport n'apparaît.
## 17. Fermeture opérateur `pre.005` et matérialisation `pre.006`
### 17.1 Fermeture opérateur de `pre.005`
Le journal opérateur communiqué le 8 septembre 2026 ferme `0.3.11-pre.005` (`workspace.package.version = 0.3.11-pre.5`) :
```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, 780 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 : 11 unit + 3 dependency-boundary + 4 public API PASS, 0 échec
doc-tests : PASS
cargo tree normal : conforme au firewall attendu
cargo tree features : Tokio limité à macros/rt/sync/time côté Worker et Store sans backend Worker direct
```
`pre.006` peut donc être ouverte.
### 17.2 Admission centrale bornée
Le supervisor crée exactement un channel central :
```text
tokio::sync::mpsc::channel<RawTransactionIngress>(admission_queue_capacity)
```
`RawTransactionIngress` reste crate-private et n'appartient pas à l'API publique. Le receiver owner `RawTransactionAdmission` est également crate-private ; le seam source reçoit directement un clone du `tokio::sync::mpsc::Sender<RawTransactionIngress>` avec son `watch<bool>` de stop.
Le contrat d'admission est :
```text
mpsc::Sender::send(...).await pour le backpressure
source harness : select! biased avec stop avant send
receiver close au shutdown
aucun unbounded_channel
aucun drop silencieux sous saturation normale
```
Le supervisor continue à observer le stop en priorité. Lors de la fermeture, le receiver appelle `close()`, refuse toute nouvelle admission, puis canonicalise les entrées déjà présentes dans le buffer avant le join final des tâches enfants.
### 17.3 Ingress privé et common RAW
L'ingress de fondation porte uniquement :
```text
RawTransactionMaterial
RawNetworkId attendu
RawAcquisitionProvenance sûre
source key opaque [u8; 32]
```
Le pipeline `pre.006` est :
```text
vérifier ingress.network == settings.network
canonicalize_raw_transaction(material)
vérifier transaction.reference.network == settings.network
dériver RawObservationKey Worker-owned
assemble_raw_transaction_acquisition(transaction, observation_key, provenance)
```
Aucune logique de canonicalisation RAW v1 n'est recodée dans le Worker. Une erreur common RAW est réduite à un contexte runtime statique et n'échoe aucun payload, réseau ou signature.
### 17.4 Observation key privée V1
Le domaine exact est :
```text
ksp.raw_transaction_ingest.observation.v1\0
```
L'entrée SHA-256 est domain-separated puis encode avec longueur `u64` big-endian :
```text
network UTF-8
signature 64 bytes
source key 32 bytes
```
Aucun timestamp local, run id ou ordre d'admission n'entre dans la clé. Une rediffusion du même triplet produit donc la même `RawObservationKey`; le contrat provider/source public reste reporté à `0.3.12`.
Golden harness figé :
```text
network : mainnet
signature : 64 x 0x07
source key : 32 x 0x09
SHA-256 : f8d161dca8a8a72a0da110fc87882ee7136848461c6aa32b09e30a6188b95dcc
```
### 17.5 Preuves ajoutées
Les tests unitaires `pre.006` couvrent :
```text
capacity = 1 : second send reste bloqué tant que le premier slot n'est pas consommé
stop : un sender bloqué retourne false sans admission post-stop
common RAW : payload canonique exact + format/version exacts
observation key : golden exact
assembly : transaction/provenance/reference alignés
network guard : mismatch ingress et mismatch material rejetés sans fuite de valeurs
```
Le test de dependency boundary exige désormais `mpsc`, common canonicalization, common assembly et le domaine observation, tout en interdisant toujours persistence, mode Store, Transport, snapshots et `unbounded_channel`.
### 17.6 Frontière volontaire de `pre.006`
La tranche n'introduit encore aucun :
```text
RawTransactionWrite::persist_raw_transaction_acquisition
RawTransactionAcquisitionMode::Normal
persistence concurrency
Store outcome mapping
content conflict terminal
store failure terminal
snapshot concret / compteurs publics
source live / Transport
Config
retry/reconnect/gap repair
```
`pre.007` reste propriétaire de la persistence et des outcomes. `pre.008` reste propriétaire des snapshots. `pre.009` reste propriétaire du fault ordering immédiat et du drain timeout/abort.
### 17.7 Preuves locales d'assemblage `pre.006`
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 (340 table(s), 781 file(s))
scan statique production : aucun ?, unwrap, expect, panic, unbounded_channel
scan statique scope : aucune persistence Store, aucun Transport, aucun snapshot concret
scan statique pipeline : exactement un mpsc::channel, un appel common canonicalize et un appel common assembly
golden SHA-256 indépendant : f8d161dca8a8a72a0da110fc87882ee7136848461c6aa32b09e30a6188b95dcc
```
L'environnement d'assemblage ne fournit ni `cargo`, ni `rustc`, ni `rustfmt`. Aucun gate Cargo `pre.006` n'est déclaré PASS localement.
### 17.8 Gate opérateur demandé pour `pre.006`
```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
cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal
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.