# Delta `0.3.14-pre.010` — backpressure et fairness nominal / repair ## Base requise ```text 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 : ```text 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 : ```text 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` : ```text 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 : ```text 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 : ```text premier arbitrage -> Nominal après Nominal -> Repair après Repair -> Nominal ``` Le burst repair maximal en présence de nominal est donc : ```text 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 : ```text hydration_permits ``` est maintenant précédé par l'arbitre nominal/repair. Le chemin live existant acquiert explicitement : ```text 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 : ```text admission_queue_capacity = 1 persistence_concurrency = 1 ``` Le fanout bloc repair dérive uniquement de la capacité existante : ```text repair_block_fetch_limit(existing_capacity) = min(existing_capacity, 4) ``` Donc : ```text 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 : ```text 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 : ```text 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 : ```text 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 : ```text 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é ```text 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 ```text deltas/0.3.14/pre.010.md ``` ## Fichiers modifiés ```text 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 ```text aucun ``` ## Version Cargo Conformément à `VER-ID-009` : ```text 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 : ```text 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 ```text 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 ```text 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 ```text aucune pour cette tranche ``` ## Gate opérateur après application ```bash 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 ```