# Delta 0.3.13-pre.009 — disagreements, duplicate storms, bornes globales et fairness ## Base requise ```text livraison précédente : 0.3.13-pre.008-fix.002 Cargo base : 0.3.13-pre.8.fix.2 delta base : deltas/0.3.13/pre.008-fix.002.md archive delta base : ksp-general-0.3.13-pre.008-fix.002.zip ``` Les gates opérateur communiqués le 10 septembre 2026 autorisent cette tranche. Le gate Worker est vert pour `cargo fmt`, `cargo fmt --check`, les audits Rust/Markdown, `cargo check --workspace`, Clippy strict et toutes les suites `ksp-worker-raw-transaction-ingest-lib` : `94` unit, `4` cross-layer, `15` dependency-boundary, `22` hardening, `16` public-api, `4` release-completeness et `0` doc-test. Le gate étendu complète cette qualification avec `cargo test -p ksp-onchain-transport-lib` : `389` unit, `52` public-api, `44` release-completeness et `4` doc-tests passent. Les cinq smokes réseau opt-in affichés restent ignorés comme prévu. Les commandes `cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal`, `cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features` et `cargo tree --duplicates` sont exécutées sans erreur ; `cargo tree --duplicates` liste les doublons existants du workspace sans introduire de promesse de graphe sans doublon. ## Objectif Fermer les risques adversariaux qui restent après la convergence cross-source de `pre.008` : ```text disagreement entre sources storms de références dupliquées borne globale des pending hydration signals borne globale des tâches/hydrations HTTP cleanup d'un leader global annulé fairness minimale entre sources reference-bearing absence de starvation structurelle ``` La tranche ne modifie pas encore la projection publique de health/snapshots multi-source ; ce point reste réservé à `pre.010`. ## Version ```text livraison : 0.3.13-pre.009 workspace.package.version : 0.3.13-pre.9 archive : ksp-general-0.3.13-pre.009.zip ``` `Cargo.toml` passe de la version de fichier `555` à `556`. ## Budgets globaux et fairness minimale Yellowstone, Standard Logs et Helius Transaction sont les sources reference-bearing qui nécessitent une hydration `getTransaction`. Avant tout spawn, `run_live_sources` vérifie : ```text hydration_source_count <= admission_queue_capacity hydration_source_count <= persistence_concurrency ``` Si une de ces relations est fausse, le démarrage échoue fail-closed avec un `runtime_invalid` stable. Aucune capacité configurée n'est agrandie silencieusement. Lorsque la composition est valide, les deux budgets sont partitionnés statiquement par quotient/reste suivant l'ordre déjà validé des sources : ```text somme hydration pending quotas = admission_queue_capacity somme hydration in-flight quotas = persistence_concurrency quota de chaque source reference-bearing >= 1 ``` Une source ne peut donc pas consommer la part réservée aux autres sources reference-bearing. Ce mécanisme n'introduit ni scheduler pondéré, ni priorité provider, ni primary/standby. Standard Block et HTTP Block Polling restent RAW-direct et continuent à utiliser l'admission centrale bornée sans passer par ces quotas d'hydration. ## Borne globale d'hydration Le `RawTransactionIngestGlobalHydrationRegistry` reste privé et borné à `admission_queue_capacity` clés distinctes. Un duplicate storm sur une clé déjà présente rejoint le résultat global existant et ne crée ni nouvelle entrée ni second leader HTTP. Un `tokio::sync::Semaphore` global, dimensionné à `persistence_concurrency`, protège en plus le nombre de leaders HTTP effectivement ouverts. Les coordinators locaux conservent simultanément leurs quotas `max_pending_signals` et `max_in_flight`. Une clé distincte au-delà de la borne globale produit `source.global_hydration_pending_saturated` au lieu d'une croissance mémoire non bornée. ## Cleanup d'un leader global Chaque leader de la registry possède un `RawTransactionIngestHydrationLeaderGuard` privé. Si la tâche est annulée ou droppée avant la publication normale du résultat, le guard publie une faute source sûre aux followers et retire la clé du registre. Après cleanup, la même clé peut redevenir leader lors d'une acquisition ultérieure. Aucun leader orphelin ne doit survivre à un abort/shutdown. ## Disagreement canonique Le cache run-local de convergence persistence ne compare plus uniquement `RawContentHash`. Pour une même identité durable `(network, signature)`, il mémorise maintenant un état canonique borné : ```text slot block_time format_id format_version content_hash ``` Une divergence sur l'une de ces dimensions produit immédiatement le content conflict terminal existant avant toute observation additionnelle. Aucun byte de transaction n'est recopié dans le cache ; le hash provient de la canonicalisation Common RAW et le Store conserve son contrôle durable final sur le contenu exact. La politique reste conservatrice : aucune majorité de sources, aucun first-provider-wins, aucune préférence provider/tier et aucun overwrite de conflit. ## Fairness et duplicate storms La fairness minimale est prouvée sur le canal d'admission commun borné à capacité `1`. Après qu'une source en storm a rejoint la file d'attente, une seconde source déjà prête rejoint la même file et progresse avant la répétition suivante de la storm. Cette preuve ne revendique pas une QoS pondérée. Elle verrouille uniquement l'absence de starvation indéfinie d'une source déjà prête sous le contrat FIFO du canal borné commun, tandis que les quotas statiques empêchent la starvation structurelle des sources reference-bearing en amont. ## Preuves ajoutées Tests unitaires déterministes : ```text budgets 8/5 répartis sur 3 sources -> [3,3,2] pending et [2,2,1] in-flight composition sous-provisionnée -> refus avant spawn 32 duplicats d'une même clé -> un seul leader global clé distincte au-delà de max_pending -> saturation sûre sémaphore capacité 1 -> une seule permit simultanée leader guard droppé -> Failed publié + clé réouvrable queue admission capacité 1 -> seconde source prête progresse sous storm même signature + slot divergent -> content conflict même signature + block_time divergent -> content conflict même signature + contenu/hash divergent -> content conflict aucune observation additionnelle après disagreement ``` Canaris externes : ```text dependency_boundary : bornes/fairness restent dans Worker + façades existantes hardening : quotas, sémaphore, cleanup, disagreement et absence de provider preference public_api : registry, leader guard, quotas et canonical state restent privés release_completeness : présence obligatoire des trois canaris pre.009 ``` ## Frontière de tranche `pre.009` ne ferme pas encore : ```text nouveaux compteurs/health publics multi-source projection détaillée par source politique de dégradation non terminale failover provider scheduler/QoS pondéré source primary/standby majority vote ``` Les snapshots/health appartiennent à `pre.010`. ## Fichiers modifiés ```text Cargo.toml crates/ksp-worker-raw-transaction-ingest-lib/README.md crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md crates/ksp-worker-raw-transaction-ingest-lib/src/persistence.rs crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs crates/ksp-worker-raw-transaction-ingest-lib/tests/dependency_boundary.rs crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs crates/ksp-worker-raw-transaction-ingest-lib/tests/public_api.rs crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/admission.rs crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/persistence.rs crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs docs/plans/034-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE_PLAN.md docs/validation/030-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE.md ``` ## Fichiers ajoutés ```text deltas/0.3.13/pre.009.md ``` ## Fichiers supprimés ```text aucun ``` ## Validation dans l'environnement d'assemblage Le toolchain Rust/Cargo/Rustfmt n'est pas disponible dans l'environnement d'assemblage. Les commandes Cargo post-`pre.009` restent donc `NON EXÉCUTÉ LOCAL`. Les audits statiques KSP, le scan normatif, le contrôle exhaustif du diff, des headers et du ZIP sont exécutés avant livraison. ## Résultats statiques finaux ```text General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean Markdown table audit: clean (340 tables, 845 files) Normative rule definitions: 489 Unique normative IDs: 489 Duplicates: 0 ``` Contrôle ciblé : ```text 14 fichiers existants modifiés 1 fichier ajouté 0 suppression 14/14 headers existants : +1 nouvelle dépendance : aucune backend Store physique direct : absent client HTTP/gRPC direct : absent unbounded_channel : absent registry/quotas/canonical state publics : absents ``` ## Gate opérateur requis avant pre.010 ```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-onchain-transport-lib 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 cargo tree --duplicates ```