Files
2026-09-12 14:20:02 +02:00

7.8 KiB

Delta 0.3.14-pre.010 — backpressure et fairness nominal / repair

Base requise

0.3.14-pre.009-fix.002
workspace.package.version = 0.3.14-pre.9.fix.2
deltas/0.3.14/pre.009-fix.002.md présent

Gate de la base

Le gate opérateur de 0.3.14-pre.009-fix.002 est validé avant ouverture de cette tranche :

cargo fmt --all : PASS
cargo fmt --all -- --check : PASS
audit Rust workspace rules : PASS
audit Markdown tables : PASS
cargo check --workspace : PASS
cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS
cargo test -p ksp-worker-raw-transaction-ingest-lib --all-targets --all-features : PASS

Le gate Worker comprend notamment :

143 unit tests : PASS
cross_layer_completeness : 8 PASS
dependency_boundary : 19 PASS
hardening : 34 PASS
public_api : 20 PASS
release_completeness : 11 PASS

Objectif

Implémenter strictement la tranche pre.010 du plan 035 :

conserver une admission Common RAW centrale unique
conserver un pipeline de persistence unique et ses limites existantes
faire partager au trafic nominal et repair le registre/coalescence global d'hydration existant
ordonner nominal/repair sans réserver une fraction fixe de capacité
permettre la progression lorsque la capacité existante vaut 1
borner le burst repair lorsqu'un nominal attend
conserver un fanout logique getBlock <= 4
conserver les fenêtres HTTP <= 512 slots
ne créer aucun second pool Store, aucune seconde queue d'admission et aucun second registre d'hydration

Arbitre privé nominal / repair

runtime_resources.rs introduit un arbitre privé source-neutral :

RawTransactionIngestTrafficClass
    Nominal
    Repair

RawTransactionIngestFairTurnGate

Les waiters reçoivent des tickets monotones checked. La queue d'attente est bornée par la capacité déjà attribuée au registre global d'hydration ; aucun waiter pool illimité n'est ajouté.

Lorsque les deux classes attendent :

premier arbitrage -> Nominal
après Nominal      -> Repair
après Repair       -> Nominal

Le burst repair maximal en présence de nominal est donc :

MAX_RAW_TRANSACTION_INGEST_REPAIR_BURST = 1

Si une seule classe attend, elle progresse sans attendre artificiellement l'autre classe. Le mécanisme ne réserve donc jamais une capacité inexistante.

Hydration globale partagée

Le RawTransactionIngestGlobalHydrationRegistry reste unique.

Le même sémaphore :

hydration_permits

est maintenant précédé par l'arbitre nominal/repair. Le chemin live existant acquiert explicitement :

RawTransactionIngestTrafficClass::Nominal

La classe Repair utilise la même primitive d'acquisition et le même sémaphore ; aucun RepairHydrationRegistry, aucune seconde semaphore d'hydration et aucune seconde coalescence ne sont créés.

L'arbitre gouverne l'ordre d'accès au permit ; le permit lui-même reste détenu pendant l'I/O comme auparavant. Les bornes globales existantes restent donc l'autorité de concurrence.

Faible capacité et fanout HTTP

La validation run-local accepte explicitement :

admission_queue_capacity = 1
persistence_concurrency = 1

Le fanout bloc repair dérive uniquement de la capacité existante :

repair_block_fetch_limit(existing_capacity) = min(existing_capacity, 4)

Donc :

capacité 1  -> fanout 1
capacité 4  -> fanout 4
capacité 64 -> fanout 4

Aucun worker ou permit n'est réservé à l'avance pour le repair. La borne historique reste également :

MAX_RAW_TRANSACTION_INGEST_REPAIR_ACTIVE_GAPS = 1
MAX_RAW_TRANSACTION_INGEST_REPAIR_BLOCK_FETCH_IN_FLIGHT = 4
MAX_RAW_TRANSACTION_INGEST_REPAIR_DISCOVERY_WINDOW_SLOTS = 512

Admission et persistence

Cette tranche ne crée aucune nouvelle mpsc::channel dans runtime_resources.rs.

Tout matériau Common RAW continue à utiliser :

RawTransactionAdmission
la Sender centrale existante
le pipeline de persistence existant
la même persistence_concurrency

La fairness ajoutée ne contourne donc ni backpressure admission ni convergence/persistence Store.

Compteurs et overflow

Les tickets de fairness utilisent checked_add. Un épuisement de ticket ou un dépassement de la queue de waiters produit une erreur Worker stable ; aucun saturating_add n'est utilisé pour masquer un overflow.

L'annulation d'un waiter retire son ticket de l'arbitre. La libération d'un turn réveille les waiters restants sans conserver de std::sync::MutexGuard à travers un await.

Tests ajoutés

Les unit tests Worker couvrent :

alternance Nominal -> Repair -> Nominal lorsque les deux classes attendent
burst repair borné à 1
queue de waiters bornée et libérée après annulation/drop
fanout bloc min(capacité, 4)
partage réel du même semaphore d'hydration entre Nominal et Repair
blocage Repair tant que le permit capacity=1 est occupé par Nominal
progression Repair seul avec capacity=1

Les canaris hardening et release_completeness vérifient en plus :

une seule admission mpsc centrale
un seul RawTransactionIngestGlobalHydrationRegistry
absence de RepairHydrationRegistry
bornes 4 getBlock / 512 slots conservées
aucune fuite publique des classes ou de l'arbitre de fairness

Hors périmètre inchangé

aucune nouvelle snapshot publique de gap/repair avant pre.011
aucun changement de health policy pre.009
aucun nouveau mécanisme replay/reconnect Worker
aucun respawn de source
aucun EARLY/shred
aucun Job Backfill depuis Worker
aucun nouveau provider ou SDK
aucune nouvelle dépendance

Fichiers ajoutés

deltas/0.3.14/pre.010.md

Fichiers modifiés

Cargo.toml
crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs
crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs
crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs

Fichiers supprimés

aucun

Version Cargo

Conformément à VER-ID-009 :

header Cargo.toml : 581 -> 582
workspace.package.version : 0.3.14-pre.9.fix.2 -> 0.3.14-pre.10

Versions des fichiers modifiés :

runtime_resources.rs : 39 (bump depuis 38)
unit_tests/runtime_resources.rs : 32 (bump depuis 31)
tests/hardening.rs : 34 (bump depuis 33)
tests/release_completeness.rs : 29 (bump depuis 28)

Validation exécutée dans l'environnement de préparation

python3 scripts/audit_rust_workspace_rules.py : PASS
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas : PASS
scan des frontières Worker/Transport/Backfill/Store : PASS
scan de la crate-root historique : PASS
comparaison exacte pre.009-fix.002 -> pre.010 : PASS

Les gates Cargo ne sont pas déclarés PASS dans l'environnement de préparation lorsqu'ils ne peuvent pas y être exécutés. Ils restent obligatoires côté opérateur avant pre.011.

Décisions prises

fairness temporelle/alternée et non réservation de pourcentage
burst repair = 1 lorsque nominal attend
classe seule autorisée à progresser immédiatement
hydration nominal et repair sur le même registre + semaphore
fanout bloc dérivé de la capacité existante et plafonné à 4
aucune nouvelle queue admission/persistence

Questions ouvertes

aucune pour cette tranche

Gate opérateur après application

cargo fmt --all
cargo fmt --all -- --check
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 --all-targets --all-features