v0.3.11-pre.008

This commit is contained in:
2026-09-08 12:28:51 +02:00
parent ed6c0ac10c
commit 22c88c449d
13 changed files with 1241 additions and 88 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/032-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION_PLAN.md -->
<!-- version: 7 -->
<!-- version: 8 -->
# Plan v0.3.11 — fondation runtime du Worker RawTransaction ingest
@@ -732,12 +732,14 @@ Budget cible : **1520 min**. `mpsc` borné, backpressure, ingress privé, com
Budget cible : **1520 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`.
État après matérialisation : **implémenté et gate opérateur validé**. 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. Le gate communiqué le 8 septembre 2026 est vert sur `fmt`, audits, `check`, Clippy strict, 31 tests de crate et doc-tests. Aucun arbre Cargo n'a été requis car aucune dépendance/feature n'avait changé. Les races terminales fortes et le timeout/abort restent réservés à `pre.009`.
### `pre.008` — snapshots concrets + projection Worker API
Budget cible : **1520 min**. `watch` latest-value, compteurs checked, common projection, slow/no listener et terminal retained.
État après matérialisation : **implémenté, gate opérateur requis**. La crate expose `RawTransactionIngestSnapshot` et `RawTransactionIngestSnapshotSource`, ce dernier implémentant directement `ksp-worker-api::WorkerSnapshotSource`. Un unique `watch<RawTransactionIngestSnapshot>` porte la valeur latest-value concrète ; `wait_terminal()` lit ce même flux, supprimant le watch terminal spécialisé de `pre.004`. La séquence `WorkerSnapshotSequence` est donc identique pour la vue concrète et la projection commune. Les compteurs `u64` sont incrémentés par checked-add au point exact où le supervisor dequeue/canonicalise ou récolte une persistence ; l'épuisement devient `worker_raw_transaction_ingest.counter_exhausted`. Les profondeurs de queue et de persistence sont dérivées des structures bornées existantes, sans tâche de monitoring ni seconde event queue. `source_failure_total` et `backpressure_wait_total` existent dans le contrat sûr mais restent à zéro dans cette tranche source-neutral ; `pre.009` est propriétaire du fault source et de l'instrumentation de saturation. Les tests couvrent projection common/concrete, listener lent coalescé, terminal retenu, counters de pipeline réussi et Store fault projeté `Unhealthy`.
### `pre.009` — hardening shutdown/backpressure/fault races
Budget cible : **1520 min**. Drain deadline, stop/fault ordering, saturation, source failure, Store slow/failure, abort+join au timeout, no orphan tasks. Scinder immédiatement si le gate réel dépasse le budget.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/028-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION.md -->
<!-- version: 10 -->
<!-- version: 11 -->
# Validation v0.3.11 — fondation runtime du Worker RawTransaction ingest
@@ -1173,3 +1173,131 @@ 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.
## 19. Fermeture opérateur `pre.007` et matérialisation `pre.008`
### 19.1 Fermeture opérateur de `pre.007`
Le journal opérateur communiqué le 8 septembre 2026 ferme `0.3.11-pre.007` (`workspace.package.version = 0.3.11-pre.7`) :
```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, 783 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 : 23 unit + 3 dependency-boundary + 5 public API PASS, 0 échec
doc-tests : PASS
```
Aucune dépendance ni feature n'avait changé dans `pre.007`; aucun `cargo tree` intermédiaire n'était requis. `pre.008` peut donc être ouverte.
### 19.2 Snapshot concret latest-value unique
`pre.008` introduit `RawTransactionIngestSnapshot` avec uniquement des données sûres : projection commune Worker, capacités/profondeurs bornées et compteurs monotones. Un seul :
```text
tokio::sync::watch::channel<RawTransactionIngestSnapshot>
```
porte la valeur latest-value concrète. Le handle ne conserve plus de watch terminal séparé : `wait_terminal()`, `snapshot_source()` et `worker_snapshot_source()` lisent le même flux.
Le source concret implémente directement `ksp_worker_api::WorkerSnapshotSource`; la même `WorkerSnapshotSequence` pilote donc les deux vues sans adaptation de sequence ou deuxième queue d'événements.
### 19.3 Compteurs checked et profondeurs runtime
Les compteurs de `RawTransactionIngestSnapshot` sont des `u64` monotones :
```text
admitted_total
canonicalized_total
persisted_total
entity_inserted_total
entity_already_present_total
entity_skipped_purged_total
observation_inserted_total
observation_already_present_total
content_conflict_total
store_failure_total
source_failure_total
backpressure_wait_total
```
Chaque incrément effectivement utilisé dans `pre.008` passe par `checked_add(1)`. L'épuisement ne wrappe jamais et devient :
```text
worker_raw_transaction_ingest.counter_exhausted
```
`admission_queue_depth` est lu directement depuis le receiver `mpsc` borné et `in_flight_persistence` depuis le `JoinSet` privé de persistences. Aucun polling, aucune tâche métrique et aucune queue de télémétrie ne sont ajoutés.
`source_failure_total` et `backpressure_wait_total` restent à zéro dans cette tranche source-neutral. Leur instrumentation comportementale appartient à `pre.009`, qui possède le fault source, la saturation et les races shutdown/fault.
### 19.4 Mapping Worker API
Mapping conservé :
```text
Starting -> health Unknown / activity Unknown si vide
Running sans fault -> health Healthy
Stopping -> conserve le dernier health non terminal
Faulted -> health Unhealthy
queue > 0 ou persistence > 0 -> activity Active
Running/Stopping terminalement vide -> activity Idle
```
Le terminal n'est publié qu'après le drain/join déjà possédé par le supervisor. La valeur terminale reste lisible après drop du publisher grâce à la sémantique latest-value de `watch`.
### 19.5 Preuves ajoutées
Les tests `pre.008` couvrent :
```text
snapshot initial Starting exact
projection common == snapshot concret pour la même sequence
compteurs/capacités initialement exacts
checked counter exhaustion -> counter_exhausted sans wrap
listener lent -> coalescence sur la dernière sequence
terminal concret retenu après fermeture du publisher
handle.snapshot_source() public
handle.worker_snapshot_source() public et WorkerSnapshotSource Send + Sync
pipeline runtime réussi -> admitted/canonicalized/persisted/outcomes exacts
Store failure terminal -> snapshot Unhealthy + store_failure_total
absence de nouveau dependency edge
un seul watch snapshot concret, aucun backend direct ni Transport
```
### 19.6 Frontière volontaire de `pre.008`
La tranche n'introduit toujours aucun :
```text
source live
Transport
Config
backend Store direct
source_failed public
source failure behavior
backpressure wait instrumentation productive
drain timeout / abort forcé
fault/stop precedence finalisée
retry / reconnect / gap repair
```
`pre.009` reste propriétaire du hardening shutdown/backpressure/fault races.
### 19.7 Gate opérateur demandé pour `pre.008`
Aucune dépendance ni feature n'est modifiée par `pre.008`; 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 : snapshots common/concrete latest-value, compteurs checked, terminal retenu et absence de nouveau boundary crossing sont verts.