# Delta `0.3.14-pre.006` — discovery HTTP bornée pour continuité ## Base requise ```text 0.3.14-pre.005 workspace.package.version = 0.3.14-pre.5 deltas/0.3.14/pre.005.md présent ``` ## Gate de la base Le gate opérateur de `0.3.14-pre.005` 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 124 unit tests : PASS cross_layer_completeness : 8 PASS dependency_boundary : 19 PASS hardening : 30 PASS public_api : 20 PASS release_completeness : 7 PASS ``` ## Objectif Implémenter strictement la tranche `pre.006` du plan `035` : ```text détecter les primitives HTTP de scan réellement disponibles sur le rôle same-network borner chaque fenêtre de discovery à 512 slots inclusifs préférer getBlocks(start,end) lorsqu'il est réellement supporté utiliser getBlocksWithLimit uniquement avec une preuve de progression issue de sa propre réponse ne jamais utiliser getSlot seul comme preuve de queue skipped réutiliser getBlock observed pour les slots explicitement produits conserver getBlock = null comme obstacle, jamais comme slot skipped ne pas élargir un scope filtré vers FullLedgerTransactions ne pas modifier encore la politique de supervisor ou de health ne pas introduire de logique caller-driven de backfill ``` ## Capability HTTP run-wide `runtime_resources.rs` matérialise maintenant un inventaire privé : ```text RawTransactionIngestHttpScanCapabilities get_block get_blocks get_blocks_with_limit get_slot ``` Le choix de primitive est conservative : ```text getBlock + getBlocks -> ClosedRange getBlock + getBlocksWithLimit + getSlot -> WithLimitBoundary autres combinaisons -> scan indisponible ``` `ClosedRange` est toujours préféré lorsque les deux stratégies sont disponibles. La détection reste fondée sur le snapshot Transport du rôle exact et du cluster attendu. La seule présence d'un pool HTTP ne crée donc aucune capability implicite. ## Fenêtres bornées La borne canonique de `continuity.rs` reste : ```text MAX_RAW_TRANSACTION_INGEST_REPAIR_DISCOVERY_WINDOW_SLOTS = 512 ``` Un alias crate-wide de même valeur est ajouté uniquement pour que `runtime_resources.rs` réutilise cette borne sans la dupliquer : ```text MAX_RAW_TRANSACTION_INGEST_CONTINUITY_DISCOVERY_WINDOW_SLOTS ``` Une fenêtre : ```text est inclusive rejette end < start rejette les overflows rejette plus de 512 slots ``` La source HTTP polling productive réutilise désormais cette primitive. Sa valeur `max_discovered_blocks_per_cycle` reste une borne supérieure ; une fenêtre productive ne dépasse jamais le minimum entre cette valeur et `512` slots. ## Stratégie `ClosedRange` Lorsque `getBlocks` est supporté, le Worker appelle : ```text getBlocks(start_slot, end_slot, commitment) ``` Une réponse réussie constitue une preuve fermée de la fenêtre RPC demandée. Les slots absents de la liste sont alors qualifiables comme `skipped/non-produced` uniquement à l'intérieur de cette fenêtre. Tout slot retourné au-delà de `end_slot` est rejeté comme violation d'invariant. ## Stratégie `WithLimitBoundary` Lorsque seul le chemin `getBlocksWithLimit` qualifié est disponible : ```text getSlot(commitment) getBlocksWithLimit(start_slot, window_slot_count, commitment) ``` `getSlot` indique uniquement la position du cluster observée par ce rôle. Il ne ferme jamais à lui seul la queue de la fenêtre. La preuve avance seulement jusqu'au dernier slot produit effectivement énuméré par la réponse `getBlocksWithLimit` : ```text last_discovered < end_slot -> preuve partielle jusqu'à last_discovered last_discovered >= end_slot -> fenêtre cible entièrement prouvée aucun slot découvert -> aucune preuve de tail, même si getSlot >= end_slot ``` Ainsi, une queue constituée uniquement de slots skipped n'est pas inventée à partir de deux réponses pouvant provenir de routes HTTP différentes. La fenêtre restera en attente jusqu'à ce qu'une primitive plus forte ou un bloc ultérieur fournisse une borne observable. ## `getBlock observed` Chaque slot explicitement produit continue à passer par : ```text HttpTransportPool::get_block_observed ``` Les règles existantes restent inchangées : ```text Some(block) -> projection Common RAW puis admission centrale None -> la progression se bloque sur ce slot le slot n'est pas reclassé skipped ``` Aucun second pipeline de persistence n'est ajouté. ## Scope et intégration Cette tranche utilise immédiatement la primitive bornée uniquement dans `RawTransactionIngestHttpBlockPollingSource`, dont le scope est déjà `FullLedgerTransactions`. Pour Yellowstone, Standard Logs et Helius Transaction, la détection run-wide de capability HTTP demeure disponible dans les continuity descriptors, mais aucun scan full-block n'est déclenché ici. Leur activation dépendra de la preuve de scope et de la réconciliation des tranches suivantes. `Standard Block` conserve l'absence de pool HTTP attaché. La politique de terminalité des incidents `pre.003/pre.004` n'est pas encore remplacée. `pre.008` reste responsable de l'intégration supervisor/gap-ledger. ## Tests ajoutés Les unit tests Worker couvrent : ```text préférence ClosedRange sur fallback capability fallback complète obligatoire capability détectée par rôle sans I/O fenêtre inclusive 1..512 rejet 513 slots, range inversé et overflow ClosedRange vide comme preuve de slots skipped dans la fenêtre exacte rejet d'un résultat ClosedRange au-delà de end_slot fallback dépassant end_slot et filtrage de la cible fallback partiel ne prouvant que jusqu'au dernier slot énuméré getSlot seul + réponse vide ne prouvant aucune queue absence de getSlot dans le fallback rejetée ``` Les canaris `hardening` et `release_completeness` garantissent en plus : ```text présence des deux stratégies HTTP usage borné de getBlocks/getBlocksWithLimit réutilisation de getBlock observed absence de dépendance Job Backfill absence de surface publique de discovery absence de responsabilité repair lower-case dans la crate-root historique ``` ## Hors périmètre inchangé ```text aucun moteur de reconciliation supervisor aucun changement health public aucune hydration repair getTransaction dans cette tranche aucune source/provider supplémentaire aucun EARLY/shred adapter aucun backfill historique caller-driven ``` ## Fichiers ajoutés ```text deltas/0.3.14/pre.006.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-worker-raw-transaction-ingest-lib/src/continuity.rs crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs 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 : 572 -> 573 workspace.package.version : 0.3.14-pre.5 -> 0.3.14-pre.6 ``` Versions des fichiers modifiés : ```text continuity.rs : 5 -> 6 lib.rs : 29 -> 30 runtime_resources.rs : 31 -> 32 unit_tests/runtime_resources.rs : 25 -> 26 tests/hardening.rs : 29 -> 30 tests/release_completeness.rs : 24 -> 25 ``` ## 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 ``` 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.007`. ## Prochaine tranche `pre.007` : hydration des références connues avec `getTransaction observed`, coalescence globale existante et conservation de `Missing` comme obligation non résolue ; aucun `getTransaction = null` ne devra devenir une preuve d'absence.