# Validation v0.3.12 — Yellowstone + hydration HTTP + continuité de run du Worker RawTransaction ## 1. Rôle du document Ce document enregistre les preuves réellement exécutées, les non-claims et les gates progressifs de `0.3.12`. Une commande non exécutée n'est jamais déclarée PASS. `pre.001` est un gate de lecture/audit/sizing. Il ne contient aucun code Worker réseau productif. ## 2. Gate `pre.001` — base stable ### 2.1 Archive contrôlée ```text archive : khadhroony-solana-project-v0.3.11.zip SHA-256 : a6bb59935650a7f48630d12ef80fbd1a44a84819dd129b085ff7f467369535fc bytes : 8125100 entries : 1950 unzip -t : PASS root unique : PASS absolute entries : 0 path traversal : 0 symlinks : 0 .git/ : 0 target/ : 0 node_modules/ : 0 Cargo.lock : 0 .env : 0 workspace members : 21 workspace.package.version : 0.3.11 ``` `deltas/0.3.11/rel.001.md` est présent. ### 2.2 Préconditions fonctionnelles Contrôlé dans la stable : ```text ksp-worker-raw-transaction-ingest-lib présent README/USAGE présents aucun edge Worker -> Transport aucune source réseau productive dans src/ ksp-raw-transaction-lib présent ksp-onchain-transport-lib présent avec Yellowstone gRPC générique ksp-store-lib présent ksp-job-backfill-lib ne dépend pas du Worker ``` Résultat : PASS. ## 3. Baseline statique locale avant modification Exécuté dans l'archive extraite : ```text python3 scripts/audit_rust_workspace_rules.py General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean ``` Résultat : PASS. Exécuté : ```text python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas Markdown table audit: clean (340 table(s), 798 file(s)) ``` Résultat : PASS. ## 4. Cargo local dans l'environnement d'assemblage `cargo` n'est pas installé dans l'environnement d'assemblage utilisé pour `pre.001`. Non exécuté localement : ```text cargo fmt --all -- --check cargo check --workspace cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test --workspace --all-targets --all-features cargo tree --duplicates ``` Ces commandes ne sont pas déclarées PASS localement. ## 5. Preuve opérateur de la stable `0.3.11` Le journal fourni avec la demande d'ouverture montre sur la stable : ```text cargo clean : exécuté cargo fmt --all -- --check : sans erreur visible audit Rust : clean audit Markdown : clean (340 tables, 798 fichiers) cargo check --workspace : terminé sans erreur cargo clippy --workspace --all-targets --all-features -- -D warnings : terminé sans erreur cargo test --workspace : suites affichées vertes ; tests live opt-in ignorés conformément à leur contrat cargo tree Worker normal/features : demandé dans le journal opérateur ``` Cette preuve opérateur concerne l'état stable d'entrée. Elle n'est pas réétiquetée comme exécution locale de `0.3.12-pre.001`. ## 6. Audit humain des règles Sources lues pour le gate : ```text RULES.md ROADMAP.md CHANGELOG.md docs/000-README.md docs/rules/RULES_GENERAL.md docs/rules/RULES_KSP.md docs/rules/RULES_RUST.md docs/rules/RULES_DEPENDENCIES.md docs/rules/RULES_DOCUMENTATION.md docs/rules/FILE_CONTRACTS.md docs/rules/VERSION_WORKFLOW.md docs/rules/PROMPT_STRUCTURE.md ``` Résultat : aucune divergence normative active nécessitant une correction de règle en `pre.001`. Vérifications clés : ```text D2 reste STRUCTURAL nom Worker canonique = ksp-worker-raw-transaction-ingest-lib Worker/Job restent séparés Config reste propriétaire de l'environnement et des secrets Store backend direct reste interdit au Worker VER-ID-009 impose 0.3.12-pre.1 pour cette prerelease non-fix ``` ## 7. Sources internes de handoff auditées Lecture/inventaire réalisés sur : ```text docs/plans/032-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION_PLAN.md docs/validation/028-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION.md crates/ksp-worker-raw-transaction-ingest-lib/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/ crates/ksp-worker-raw-transaction-ingest-lib/tests/ crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/ docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md docs/architecture/011-RAW_TRANSACTION_ACQUISITION.md docs/plans/031-V0_3_10_RAW_TRANSACTION_INGEST_PLAN.md docs/validation/027-V0_3_10_RAW_TRANSACTION_INGEST.md crates/ksp-raw-transaction-lib/README.md crates/ksp-raw-transaction-lib/USAGE.md crates/ksp-raw-transaction-lib/src/ crates/ksp-raw-transaction-lib/tests/ crates/ksp-onchain-transport-lib/Cargo.toml crates/ksp-onchain-transport-lib/README.md crates/ksp-onchain-transport-lib/USAGE.md crates/ksp-onchain-transport-lib/src/grpc_*.rs crates/ksp-onchain-transport-lib/src/rpc_transactions.rs crates/ksp-onchain-transport-lib/src/rpc_blocks.rs crates/ksp-onchain-transport-lib/tests/ crates/ksp-store-lib/README.md crates/ksp-store-lib/USAGE.md crates/ksp-store-lib/src/ crates/ksp-worker-api/README.md crates/ksp-worker-api/USAGE.md crates/ksp-worker-api/src/ crates/ksp-config-lib/README.md crates/ksp-config-lib/USAGE.md crates/ksp-config-lib/src/ ``` Le résultat d'inventaire est détaillé dans le plan `033`. ## 8. Preuve Worker stable Le Worker stable possède exactement huit fichiers de production sous `src/` : ```text admission.rs error.rs identity.rs lib.rs persistence.rs runtime.rs settings.rs snapshot.rs ``` Le manifest normal ne contient pas `ksp-onchain-transport-lib`, `ksp-config-lib`, `ksp-job-backfill-lib`, backend physique, Tonic, Reqwest ni Yellowstone proto. Un scan source `grpc|yellowstone|http|ws|transport` ne révèle qu'une documentation signalant l'absence de source live ; aucun adapter réseau productif n'est présent. Résultat : PASS pour la précondition `0.3.11`. ## 9. Preuve Transport actuelle Contrats existants confirmés : ```text YellowstoneGrpcChannel::open_standard_subscribe SolanaYellowstoneGrpcSubscribeSession::next_update SolanaYellowstoneGrpcSubscribeSession::snapshot YellowstoneSubscribeRequest::set_from_slot YellowstoneReplayInfo::first_available HttpTransportPool::get_transaction_observed HttpTransportPool::get_block_observed HttpObservedValue::{value, endpoint_name, provider} ``` Le snapshot Yellowstone indique explicitement : ```text continuity_gap_count : seulement gap prouvé par borne ReplayInfo replay_attempt_count : tentative, pas preuve de couverture duplicate_update_count : observabilité, duplicates toujours livrés last_requested_from_slot last_observed_slot ``` Résultat : PASS pour la réutilisation du moteur existant. ## 10. Audit externe de fraîcheur ### 10.1 Yellowstone versions Source docs.rs courante : ```text yellowstone-grpc-proto latest : 12.7.0 publication : 2026-08-29 workspace KSP : ^12.7 ``` Résultat : aucune mise à jour de dépendance nécessaire en `pre.001`. ### 10.2 Replay upstream Le changelog upstream du 22 juillet 2026 documente la correction `yellowstone-grpc-geyser 14.2.1` pour un cas où `from_slot` + `blocks` était accepté mais aucun Block replay n'était livré avant reprise live. Impact de validation : ```text subscribe accepted != replay proven from_slot sent != replay proven first_available compatible != replay proven ``` Cette menace doit posséder un canari KSP et, si un provider live est disponible, un smoke dédié. ### 10.3 Solana HTTP La documentation officielle courante confirme que `getTransaction` à `confirmed/finalized`, en Base64, fournit les champs nécessaires à la conversion Common RAW déjà qualifiée : `blockTime`, `meta`, `slot`, `transaction`, `version`. Résultat : hydration `getTransaction` maintenue comme référence P0. ### 10.4 Providers OrbitFlare documente encore Devnet gRPC et un free tier Devnet-only. Helius LaserStream documente Yellowstone wire compatibility et un replay provider-specific d'environ 216 000 slots / 24 heures. Ces valeurs ne sont pas transposées dans les constantes KSP. PublicNode reste operator-only dans KSP ; aucune nouvelle assertion provider n'est ajoutée faute de source primaire indexée suffisamment précise pendant ce gate. ## 11. Gate de matrice Yellowstone fermé ### 11.1 Transaction Preuve interne : `YellowstoneTransactionUpdate` contient slot, filter names, created_at et `YellowstoneTransactionInfo`; ce dernier contient signature, transaction, meta, index. Conclusion : candidat hydration ; RAW-direct non prouvé. ### 11.2 TransactionStatus Preuve interne : slot, signature, index, is_vote, error optionnelle. Conclusion : discovery/hydration seulement. ### 11.3 Block Preuve interne : slot, block_time, transactions avec transaction/meta/signature/index, compteurs et metadata block. Conclusion : chaque transaction peut devenir candidat hydration ; aucun pipeline block RAW parallèle. ### 11.4 BlockMeta Conclusion : continuity/health only ; aucune signature donc aucune hydration transaction autonome. ### 11.5 Slot Conclusion : continuity/health only ; aucune admission RAW. ### 11.6 from_slot Conclusion : mécanisme Transport de replay au reconnect, pas checkpoint historique Worker. ### 11.7 ReplayInfo Conclusion : `first_available` prouve seulement une limite de rétention. Un gap est prouvé quand la demande est antérieure à cette borne ; le cas inverse ne prouve pas que toutes les updates filtrées ont été livrées. ## 12. Gate architecture d'injection fermé Décision : ```text nouvel edge autorisé : Worker -> ksp-onchain-transport-lib Worker -> Config : interdit Worker -> Job : interdit Worker -> backend : interdit Worker -> Tonic/Reqwest/yellowstone-grpc-proto direct : non retenu ``` La composition supérieure construit `YellowstoneGrpcChannel`, `YellowstoneSubscribeRequest`, `HttpTransportPool` et `HttpRoleName`. `pre.002` matérialise exactement : ```text RawTransactionIngestYellowstoneSource::new(...) RawTransactionIngestRuntimeResources::new(yellowstone_source) RawTransactionIngestWorker::start_with_runtime_resources(settings, Arc, resources) ``` Les champs restent privés. `RawTransactionIngestWorker::start(settings, Arc)` reste disponible comme foundation source-neutral. Aucune API publique `enqueue` n'est ouverte. ## 13. Gate hydration/provenance fermé Hydration P0 : ```text get_transaction_observed Base64 confirmed/finalized uniquement maxSupportedTransactionVersion = 0 ``` Provenance : route composite encodée dans les champs `RawAcquisitionProvenance` existants, avec provider/endpoint réels du winner HTTP et identité sûre Yellowstone, sous `MAX_RAW_CODE_BYTES`. Aucune migration Store. Un code composite impossible à représenter est rejeté ; aucune troncature silencieuse. ## 14. Gate continuité fermé Décisions : ```text Transport high-watermark != Worker processing frontier processing frontier != blockchain completeness reconnect != replay replay != repair continuity gap prouvé => fault Worker sûr aucun Backfill automatique aucun checkpoint persistant inter-process pending hydration peut survivre au reconnect source dans le même run ``` Le split `pre.007`/`pre.008` évite de coder frontier et replay semantics dans une seule tranche. ## 15. Threat model à transformer en tests Canaris obligatoires : ```text secret/URL/header redaction remote status/error text not copied bounded signal/hydration queues bounded coalescence no duplicate HTTP in-flight for same key no double retry storm stop during connect/reconnect/hydration/replay no admission after stop frontier no orphan task after terminal counter checked arithmetic stale frontier never labelled complete continuity gap terminal and safe ``` ## 16. Smokes live ### 16.1 Disponibilité démontrée par le dépôt Présents et ignored : ```text yellowstone_orbitflare_smoke yellowstone_publicnode_smoke ``` Ils exigent des tokens fournis de manière operator-only. ### 16.2 Disponibilité opérateur pour `pre.001` Aucun secret live n'est fourni dans l'archive. Le journal stable montre ces tests comme ignorés par défaut. Résultat : ```text Worker live smoke : NON EXÉCUTÉ en pre.001 raison : pipeline productif pas encore implémenté + secret/provider live non fourni au gate ``` Aucun faux PASS live n'est enregistré. ## 17. Graphe Cargo cible vérifiable à partir de `pre.002` Attendu : ```text Worker -> core Worker -> logging Worker -> onchain-transport Worker -> raw-transaction Worker -> store facade default-features=false Worker -> worker-api Worker -> sha2 Worker -> tokio ``` Toujours absent : ```text Config Job Backfill Store backend Tauri provider SDK Tonic direct Reqwest direct Yellowstone proto direct ``` ## 18. Sizing et décision release Forecast retenu : ```text pre.001 audit/sizing/plan pre.002 Transport resource/source contract pre.003 Transaction + TransactionStatus signal adapters pre.004 HTTP hydration + provenance composite pre.005 Block + BlockMeta + Slot adapters pre.006 productive source task + supervisor/coalescence pre.007 processing frontier pre.008 reconnect/from_slot/ReplayInfo pre.009 races/retry/backpressure hardening pre.010 cross-layer completeness/security pre.011 technical/live gate pre.012 documentation reconciliation pre.013 publication preparation rel.001 ``` Décision : `0.3.12` reste ouverte et n'est pas rescindée. Toute tranche dépassant réellement 15–20 minutes est scindée avant exécution. ## 19. Validation après modification de `pre.001` Exécuté sur le delta complet : ```text python3 scripts/audit_rust_workspace_rules.py General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas Markdown table audit: clean (340 table(s), 801 file(s)) ``` Résultat : PASS pour les audits statiques locaux. Cargo reste NON EXÉCUTÉ localement car l'outil n'est pas installé. Le gate opérateur demandé après application du delta est : ```bash 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 ``` `pre.001` n'ajoutant aucun Rust, les tests ciblés Worker restent une preuve de non-régression facultative mais recommandée : ```bash 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 ``` ## 20. Non-claims `pre.001` `pre.001` ne prétend pas avoir : ```text ajouté l'edge Worker -> Transport dans Cargo ouvert une session Yellowstone dans le Worker hydraté une transaction live persisté un RAW live Yellowstone prouvé un RAW-direct Yellowstone prouvé un replay provider complet implémenté une frontier implémenté un repair enrichi les snapshots runtime exécuté un smoke live Worker exécuté Cargo dans l'environnement d'assemblage ``` ## 21. Critère de sortie `pre.001` Le gate est fermé si : ```text base stable prouvée règles auditées surfaces internes inventoriées fraîcheur externe auditée matrice Yellowstone fermée injection runtime décidée hydration/provenance décidées frontier/replay/repair distingués threat model défini smokes classifiés Cargo graph cible défini forecast <20 min par tranche maintien/split décidé plan + validation + delta créés audits statiques post-modification verts ``` ## 22. Gate opérateur reçu pour `pre.001` L'opérateur a exécuté après application de `pre.001` : ```text cargo fmt --all : sans erreur visible audit Rust : clean Rust export completeness : 0 candidate KSP workspace Rust rule audit : clean audit Markdown : clean (340 tables, 801 fichiers) cargo check --workspace : PASS visible cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS visible ``` Aucun `cargo test` ou `cargo tree` n'est présent dans ce journal ; ils ne sont donc pas revendiqués pour ce gate. Résultat : `pre.001` est accepté comme base technique de `pre.002`. ## 23. Gate `pre.002` — edge Transport + contrats runtime/source La tranche matérialise exactement : ```text workspace.package.version = 0.3.12-pre.2 Worker -> ksp-onchain-transport-lib RawTransactionIngestYellowstoneSource RawTransactionIngestRuntimeResources RawTransactionIngestWorker::start_with_runtime_resources(...) ``` Le constructeur `RawTransactionIngestYellowstoneSource::new` effectue uniquement des validations déterministes sans I/O : ```text YellowstoneSubscribeRequest::validate au moins une famille transactions / transactions_status / blocks commitment explicite confirmed ou finalized rôle HTTP configuré compatible avec le request kind get_transaction cluster identique entre Yellowstone et toutes les routes HTTP compatibles ``` `RawTransactionIngestRuntimeResources` conserve un seul source Yellowstone à champs privés et vérifie la cohérence avec `RawTransactionIngestSettings.network` avant le démarrage. `start_with_runtime_resources` préserve également le gate Store/settings existant. En `pre.002`, il ne démarre volontairement encore aucun source live : les ressources sont validées mais ne sont pas activées, puis le démarrage délègue au runtime source-neutral existant. L'activation du stream reste réservée à `pre.006` conformément au plan. ## 24. Canaris déterministes ajoutés en `pre.002` Les preuves statiques/unitaires ajoutées couvrent : ```text manifest Worker exact avec un seul nouvel edge Transport aucun Config / Job / backend Store / tonic / reqwest / yellowstone-grpc-proto direct source confirmed + transaction + getTransaction route accepté processed et commitment implicite rejetés absence de famille d'ingestion rejetée rôle HTTP sans get_transaction rejeté mismatch cluster Yellowstone/HTTP rejeté mismatch réseau Worker/source rejeté Debug sans URL, token, filter name ou client inner API publique des deux resource types disponible depuis crate root start_with_runtime_resources disponible depuis crate root aucun enqueue/send/inner/client getter public aucun open_standard_subscribe / next_update / get_transaction_observed dans la tranche Transport confiné à runtime_resources.rs dans les sources Worker ``` Aucun nouveau code Config, Store backend, Backfill ou provider n'est introduit. ## 25. Validation locale après modification de `pre.002` Exécuté dans l'environnement d'assemblage : ```text python3 scripts/audit_rust_workspace_rules.py General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean ``` L'audit Markdown est rejoué après création du delta final afin d'inclure le nouveau fichier `deltas/0.3.12/pre.002.md`. `cargo`, `rustc` et `rustfmt` ne sont pas installés dans cet environnement ; aucun gate Cargo local n'est revendiqué. Gate opérateur demandé après application du delta : ```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 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 ``` ## 26. Non-claims `pre.002` `pre.002` ne prétend pas avoir : ```text ouvert une session Yellowstone lu une update Transaction/TransactionStatus/Block émis un signal Worker privé appelé getTransaction pour hydration assemblé une provenance composite persisté une transaction issue du réseau coalescé des hydrations modifié la processing frontier branché from_slot/replay info exécuté un smoke live Worker réconcilié README/USAGE/architecture pour la surface finale 0.3.12 ``` La tranche suivante reste `pre.003` : adaptation déterministe `Transaction` + `TransactionStatus` vers le signal Worker privé, sans HTTP ni persistence réseau. ## 27. Gate opérateur reçu pour `pre.002` L'opérateur a exécuté après application de `pre.002` : ```text cargo fmt --all : sans erreur visible audit Rust : clean Rust export completeness : 0 candidate KSP workspace Rust rule audit : clean audit Markdown : clean (340 tables, 802 fichiers) cargo check --workspace : PASS visible cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS visible cargo test -p ksp-worker-raw-transaction-ingest-lib : 41 PASS, 0 fail cargo tree Worker normal : exécuté et inspecté cargo tree Worker features : exécuté et inspecté cargo tree --duplicates : exécuté ; inventaire informatif des versions dupliquées, sans gate d'unicité artificiel ``` Le graphe confirme que le Worker possède directement uniquement l'edge `ksp-onchain-transport-lib`; `reqwest`, `tonic`, `tonic-prost` et `yellowstone-grpc-proto` restent transitifs sous Transport. Résultat : `pre.002` est accepté comme base technique de `pre.003`. ## 28. Gate `pre.003` — signal privé Transaction + TransactionStatus La tranche matérialise : ```text workspace.package.version = 0.3.12-pre.3 projection Yellowstone Transaction -> signal Worker privé projection Yellowstone TransactionStatus -> même signal Worker privé aucune ouverture de stream aucune hydration HTTP aucune persistence réseau ``` Le signal reste strictement interne à `runtime_resources.rs` et n'est ni `pub`, ni `pub(crate)`, ni réexporté au crate-root. Sa forme source-neutral actuelle est : ```text network signature RawTransactionSignature slot transaction_index optionnel source family Transaction | TransactionStatus safe Yellowstone source route provider + endpoint_id matched_filter_count matched_filter_fingerprint SHA-256 déterministe created_at source-neutral optionnel seconds+nanos ``` Aucun transaction body, meta Yellowstone, `is_vote`, remote error ou payload provider n'est conservé dans ce signal. ## 29. Projection déterministe des filtres et de la route Les filter names Yellowstone sont consommés uniquement pour produire un fingerprint Worker-owned. Le calcul : ```text domain = ksp.raw_transaction_ingest.yellowstone.filters.v1\0 tri lexical des noms suppression des doublons nombre de noms uniques encodé u64 big-endian pour chaque nom : longueur u64 big-endian + bytes UTF-8 SHA-256 final ``` Le signal conserve séparément le nombre de matches reçu afin de ne pas confondre le fingerprint canonique de l'ensemble et la cardinalité de l'enveloppe reçue. La source valide aussi dès sa construction que : ```text cluster Yellowstone -> RawNetworkId représentable provider Yellowstone -> RawProvenanceCode représentable endpoint logical name Yellowstone -> RawProvenanceCode représentable ``` Une identité non représentable est rejetée par une condition Worker stable plutôt que tronquée. Cette fermeture prépare la provenance composite de `pre.004` sans modifier Store. ## 30. Canaris déterministes `pre.003` Les nouvelles preuves couvrent : ```text fixture Transaction : signature/slot/index/network/route/timestamp exacts fixture TransactionStatus : même forme sans payload ni remote error fingerprint golden exact fingerprint indépendant de l'ordre et des doublons de filter names Debug du signal sans filter name, signature brute, payload ou remote error provider/endpoint Yellowstone non représentables rejetés adapters réels typés YellowstoneTransactionUpdate / YellowstoneTransactionStatusUpdate présents TransactionStatus.error non consulté par l'adapter signal absent de la façade publique aucun open_standard_subscribe / next_update / get_transaction_observed aucun backend Store / reqwest / tonic / proto direct ajouté ``` La tranche ne modifie pas le graphe Cargo du Worker au-delà de celui déjà accepté en `pre.002`. ## 31. Validation locale et non-claims `pre.003` Exécuté dans l'environnement d'assemblage après les modifications Rust : ```text python3 scripts/audit_rust_workspace_rules.py General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) KSP workspace Rust rule audit: clean ``` L'audit Markdown est rejoué après création du delta final. `cargo`, `rustc` et `rustfmt` ne sont pas disponibles dans l'environnement d'assemblage ; aucun gate Cargo local n'est inventé. `pre.003` ne prétend pas avoir : ```text ouvert une session Yellowstone consommé une update depuis un réseau live appelé getTransaction créé une RawTransactionMaterial depuis le réseau assemblé la provenance composite Yellowstone + HTTP persisté une transaction issue de Yellowstone coalescé les hydrations traité Block / BlockMeta / Slot modifié la processing frontier branché from_slot / ReplayInfo exécuté un smoke live Worker ``` La tranche suivante reste `pre.004` : fermeture déterministe `signal -> get_transaction_observed -> Common RAW -> ingress` avec missing/mismatch et provenance composite, sans Block ni continuité/replay. ## 32. Correctif `pre.003-fix.001` — helpers préparatoires sans dead code Le gate opérateur de `pre.003` a confirmé que `cargo check --workspace` et les 45 tests Worker passaient, mais `cargo clippy --workspace --all-targets --all-features -- -D warnings` échouait sur huit warnings `dead_code` dans `runtime_resources.rs`. Les éléments concernés étaient exclusivement les adapters privés préparatoires de `pre.003` et leur fingerprint, encore sans consommateur productif avant `pre.004` : ```text RAW_TRANSACTION_INGEST_YELLOWSTONE_FILTER_FINGERPRINT_DOMAIN RawTransactionIngestSourceFamily RawTransactionIngestSourceTimestamp RawTransactionIngestSourceSignal RawTransactionIngestYellowstoneSignalView matched_filter_fingerprint project_yellowstone_signal impls Transaction / TransactionStatus associés ``` Le correctif applique directement `RUST-API-008` : ces helpers strictement privés restent présents et couverts par les unit tests de `pre.003`, mais sont compilés sous `#[cfg(test)]` jusqu'à leur première consommation de production réelle en `pre.004`. Aucun `#[allow(dead_code)]` ni `#[expect(dead_code)]` n'est ajouté. Le champ privé `route` de `RawTransactionIngestYellowstoneSource` reste, lui, productif : sa validation appartient déjà au contrat de construction `pre.003`. Il est désormais lu par le `Debug` sûr de la source, qui n'expose que les `RawProvenanceCode` déjà bornés et validés. Le correctif ne change ni la surface publique, ni le graphe Cargo, ni le scope fonctionnel de `pre.003`, et n'active toujours aucun stream Yellowstone, HTTP ou Store réseau. ## 33. Correctif `pre.003-fix.002` — canari de forme compatible avec `#[cfg(test)]` Le gate opérateur de `pre.003-fix.001` confirme que rustfmt, les audits, `cargo check --workspace`, Clippy strict et les 45 unit tests Worker passent. Le seul échec restant est le test externe `v0_3_12_pre_003_private_signal_debug_and_shape_do_not_expose_signature_filters_or_payload`. Le signal privé lui-même est correct. L'échec vient du scanner source du canari : il bornait la structure avec la séquence littérale `}\n\nimpl std::fmt::Debug ...`, alors que `pre.003-fix.001` a placé légitimement `#[cfg(test)]` entre la fermeture de la structure et son `impl Debug` afin de respecter `RUST-API-008`. Le scanner obtenait donc une chaîne vide et signalait `created_at:` comme absent. Le correctif ne touche pas au contrat de production. Le canari recherche désormais directement le début de `impl std::fmt::Debug for RawTransactionIngestSourceSignal` après la déclaration de la structure. Il reste ainsi valide avec les helpers sous `#[cfg(test)]` et restera valide lorsque `pre.004` remettra ces adapters dans le build productif. Aucun lint n'est neutralisé, aucun helper n'est remis prématurément en production et aucune fonctionnalité de `pre.004` n'est avancée. ## 34. Gate opérateur reçu pour `pre.003-fix.002` L'opérateur a exécuté après application de `pre.003-fix.002` : ```text cargo fmt --all : PASS visible audit Rust : clean Rust export completeness : 0 candidate KSP workspace Rust rule audit : clean audit Markdown : clean (340 tables, 805 fichiers) cargo check --workspace : PASS visible cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS visible cargo test -p ksp-worker-raw-transaction-ingest-lib : PASS unit tests Worker : 45 PASS, 0 fail dependency_boundary : 4 PASS hardening : 10 PASS public_api : 8 PASS release_completeness : 3 PASS doc-tests : 0 fail ``` Résultat : les deux correctifs `pre.003` sont clos et `0.3.12-pre.3.fix.2` devient la base autoritaire de `pre.004`. ## 35. Gate `pre.004` — hydration HTTP qualifiée et provenance composite La tranche porte `workspace.package.version = 0.3.12-pre.4` et ferme la qualification déterministe suivante : ```text signal Transaction / TransactionStatus -> signature canonique 64 bytes -> Base58 commun -> get_transaction_observed encoding = base64 commitment = confirmed | finalized maxSupportedTransactionVersion = 0 -> contrôle slot/index/signature embarquée -> RawTransactionMaterial source-neutral -> RawTransactionIngress existant ``` `getTransaction -> null` produit explicitement un résultat `Missing(RawTransactionReference)` et ne fabrique ni matériau RAW, ni provenance, ni ingress. Aucun retry Worker n'est ajouté autour du Transport dans cette tranche. La common RAW reçoit `format_raw_transaction_signature`, encodeur Base58 borné de `RawTransactionSignature` 64 bytes. Le round-trip avec `parse_raw_transaction_signature` est qualifié sur plusieurs signatures canoniques, y compris la signature nulle représentée par 64 caractères `1`. Le Worker n'embarque donc pas un second codec Base58. Avant toute admission, la hydration vérifie : ```text network signal == network Worker == network source route signal == route source slot HTTP == slot signal transaction_index HTTP == signal lorsqu'il est présent des deux côtés signature extraite du wire Base64 HTTP == signature signal transaction HTTP réellement encodée en Base64 ``` Un mismatch devient un fault Worker sûr `runtime_invalid` avec condition stable `hydration.*`; il n'est pas délégué au Store sous forme de content conflict. ## 36. Provenance composite `pre.004` La provenance réutilise strictement `RawAcquisitionProvenance` et `RawProvenanceCode`; aucune migration Store n'est créée. Forme qualifiée : ```text protocol = yellowstone_http provider = ys.:http. endpoint_id = ys.:http. acquisition_method = transaction_get_transaction | status_get_transaction origin = Live commitment = confirmed | finalized capture_session_id = WorkerId sûr filter_id = nom unique représentable | sha256. observed_at = created_at Yellowstone seulement s'il est représentable et <= received_at ``` Les identités HTTP proviennent de `HttpObservedValue`, donc de l'endpoint réellement gagnant après routage/retry Transport. URL, headers, token, body HTTP brut et remote error ne sont jamais copiés dans la provenance ou les diagnostics Worker. Le constructeur de `RawTransactionIngestYellowstoneSource` valide désormais que chaque route HTTP compatible peut former les codes composites provider/endpoint sans dépasser les bornes Store. Une route non représentable est rejetée ; aucune troncature n'est autorisée. ## 37. Application de `RUST-API-008` pendant `pre.004` `pre.004` ne crée toujours pas le source task productif : son ouverture reste réservée à `pre.006`. La chaîne signal/hydration n'a donc pas encore de consumer productif dans le build normal. Conformément à `RUST-API-008`, les adapters privés Transaction/TransactionStatus et le helper de hydration restent sous `#[cfg(test)]` pendant cette tranche. Ils sont exécutés par des fixtures déterministes réelles contre le `HttpTransportPool`, mais aucune fonction privée morte n'est laissée dans le build normal et aucun `#[allow(dead_code)]`/`#[expect(dead_code)]` n'est utilisé. Cela précise l'anticipation écrite dans `pre.003-fix.002` selon laquelle `pre.004` remettrait nécessairement ces helpers en production : la première consommation productive est en réalité celle du source task `pre.006`. La frontière fonctionnelle ne change pas ; seule la date d'activation de compilation productive est alignée avec la règle Rust du workspace. `pre.004` possède néanmoins deux effets productifs immédiatement valides : ```text API common RAW de formatage Base58 validation de représentabilité de la future provenance composite dans le constructeur de source ``` ## 38. Canaris déterministes `pre.004` Les nouvelles preuves couvrent : ```text round-trip Base58 64 bytes <-> texte canonique requête getTransaction avec confirmed/base64/max version 0 winner HTTP observé dans provider/endpoint composites Legacy + meta valeur + block_time valeur + index présent V0 + meta null + block_time null + index omis filter unique direct et multi-filter fingerprint borné Transaction et TransactionStatus vers méthodes de provenance distinctes created_at futur ignoré pour observed_at getTransaction null -> Missing sans ingress et sans retry Worker slot mismatch index mismatch signature wire mismatch network mismatch avant I/O absence de Block/getBlock/stream Yellowstone/source spawn absence de Config/Backfill/backend/reqwest/tonic/proto direct dans le Worker ``` ## 39. Validation locale et non-claims `pre.004` L'environnement d'assemblage exécute les audits Python et l'audit Markdown après finalisation du delta. `cargo`, `rustc` et `rustfmt` n'y sont pas disponibles ; aucun résultat Cargo local n'est inventé. `pre.004` ne prétend pas avoir : ```text ouvert open_standard_subscribe consommé une update réseau live spawn un source task Yellowstone branché Block / BlockMeta / Slot coalescé des hydrations productives modifié la processing frontier branché from_slot / ReplayInfo persisté une transaction issue d'un stream Yellowstone réel exécuté un smoke live Worker ``` La tranche suivante reste `pre.005` : adapters Block transactionnels et signaux continuity-only BlockMeta/Slot, toujours sans politique reconnect Worker. ## 40. Fix `pre.004-fix.001` — gate Clippy strict Le gate opérateur de `pre.004` confirme que `cargo check --workspace`, les audits et les suites de tests `ksp-raw-transaction-lib` / `ksp-worker-raw-transaction-ingest-lib` passent. En revanche, `cargo clippy --workspace --all-targets --all-features -- -D warnings` échoue sur trois diagnostics dans la chaîne de hydration test-only : ```text clippy::large_enum_variant sur RawTransactionIngestHydrationOutcome clippy::collapsible_if sur le contrôle optionnel transaction_index clippy::collapsible_if sur le même contrôle imbriqué ``` Le correctif ne neutralise aucun lint. `Available` stocke désormais `RawTransactionIngress` derrière `Box`, ce qui réduit la taille de l'enum de résultat test-only sans modifier le contrat fonctionnel. Les deux canaris qui transfèrent ensuite l'ingress vers `RawTransactionAdmission` déplacent explicitement la valeur hors de la box. Le contrôle d'index est réécrit avec une chaîne `if let` Rust 2024 unique : le mismatch n'est signalé que lorsque le signal possède un index, que la réponse HTTP fournit un index concret et que les deux valeurs diffèrent. La sémantique de `Omitted`/`Null` reste inchangée. Version du workspace après correctif : ```text 0.3.12-pre.4.fix.1 ``` Aucune API publique, dépendance, provenance, politique retry, surface Block/continuity ou source task productive n'est modifiée. ## 41. Gate opérateur reçu pour `pre.004-fix.001` Après application de `pre.004-fix.001`, l'opérateur a exécuté : ```text cargo fmt --all : PASS visible audit Rust : clean Rust export completeness : 0 candidate KSP workspace Rust rule audit : clean audit Markdown : clean (340 tables, 807 fichiers) cargo check --workspace : PASS visible cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS visible cargo test -p ksp-raw-transaction-lib : PASS unit tests Common RAW : 17 PASS, 0 fail integration Common RAW dependency_boundary : 2 PASS integration Common RAW public_api : 5 PASS integration Common RAW release_completeness : 2 PASS integration Common RAW security_hardening : 2 PASS cargo test -p ksp-worker-raw-transaction-ingest-lib : PASS unit tests Worker : 52 PASS, 0 fail dependency_boundary Worker : 5 PASS hardening Worker : 11 PASS public_api Worker : 8 PASS release_completeness Worker : 3 PASS doc-tests : 0 fail ``` Résultat : `0.3.12-pre.4.fix.1` devient la base autoritaire de `pre.005`. ## 42. Gate `pre.005` — Block transactionnel et continuité BlockMeta/Slot La tranche porte `workspace.package.version = 0.3.12-pre.5`. Elle reste sans source task productive et ferme trois adapters privés contre la façade Transport existante. `YellowstoneBlockUpdate` est adapté vers zéro ou plusieurs `RawTransactionIngestSourceSignal` : ```text un signal par transaction réellement incluse dans transactions[] ordre des signaux == ordre source slot == slot du Block transaction_index == index Yellowstone de la transaction signature == signature Yellowstone 64 bytes family = Block filters/created_at/network/route réutilisent les mêmes règles que Transaction/Status ``` Aucun body/meta Yellowstone du Block n'est admis directement. Ces signaux suivent la même hydration `getTransaction` que les autres familles et utilisent la méthode de provenance `block_get_transaction`. Aucun `get_block_observed` n'est introduit. `YellowstoneBlockMetaUpdate` et `YellowstoneSlotUpdate` convergent séparément vers `RawTransactionIngestContinuitySignal`, strictement continuity-only : ```text created_at family = BlockMeta | Slot matched_filter_count matched_filter_fingerprint matched_filter_id optionnel network parent_slot optionnel route slot status optionnel ``` Le signal de continuité ne contient ni signature transactionnelle, ni transaction/meta/payload, ni remote error. Pour `Slot`, les sept états Yellowstone sont mappés vers un enum Worker privé. Le texte `dead_error` n'est jamais lu ni recopié. Pour `BlockMeta`, aucun compteur n'est interprété comme preuve de complétude transactionnelle. ## 43. `RUST-API-008` et frontière productive `pre.005` Comme `pre.006` reste la première tranche qui ouvre réellement une session Yellowstone et consomme ces adapters dans le runtime normal, les nouveaux helpers `Block`/`BlockMeta`/`Slot` demeurent sous `#[cfg(test)]`. Cette décision évite simultanément : ```text code privé mort dans le build normal surface publique artificielle #[allow(dead_code)] / #[expect(dead_code)] activation prématurée du source task ``` Les impls contre les DTOs Transport réels sont néanmoins compilés dans les tests. Les fixtures génériques qualifient l'ordre, les identités et la séparation RAW/continuité sans nécessiter de constructeur public supplémentaire dans Transport. ## 44. Canaris déterministes `pre.005` Les preuves ajoutées couvrent : ```text Block -> N signaux dans l'ordre exact source signature/index/slot de chaque transaction Block conservés family Block distincte provenance hydration Block -> block_get_transaction BlockMeta -> continuity-only Slot -> continuity-only mapping exact des sept YellowstoneSlotStatus absence de signature/transaction/meta/payload/error dans le signal continuity absence de YellowstoneSlotUpdate::dead_error absence de getBlock/get_block_observed absence d'open_standard_subscribe/next_update/source spawn absence Config/Backfill/backend/reqwest/tonic/proto direct dans le Worker ``` ## 45. Non-claims `pre.005` `pre.005` ne prétend pas avoir : ```text ouvert un stream Yellowstone productif hydraté une transaction Block reçue en live coalescé Block + Transaction + TransactionStatus persisté un RAW depuis une update Block live utilisé BlockMeta ou Slot comme preuve de complétude transactionnelle branché la processing frontier interprété from_slot ou ReplayInfo détecté/réparé un gap de continuité introduit une politique reconnect Worker ``` La tranche suivante reste `pre.006` : source task productive, session Yellowstone via Transport, hydration/admission et coalescence bornée dans le supervisor existant. ## 46. Gate opérateur `pre.005` et fix `pre.005-fix.001` Le gate opérateur de `pre.005` confirme : ```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, 808 fichiers) cargo check --workspace: PASS ``` Le gate strict échoue uniquement lors de la compilation des tests Worker avant exécution : ```text error[E0599]: no method named `into_bytes` found for YellowstoneTransactionSignature ``` La façade Transport expose `YellowstoneTransactionSignature::as_bytes()`. Le même fichier `runtime_resources.rs` utilisait déjà la conversion correcte pour les updates `TransactionStatus` : ```text RawTransactionSignature::new(*update.signature().as_bytes()) ``` `pre.005-fix.001` aligne donc l'adapter `Block` sur ce contrat exact : ```text RawTransactionSignature::new(*signature.as_bytes()) ``` Aucun changement de sémantique n'est introduit : les 64 bytes canoniques sont copiés dans le même `RawTransactionSignature`; ordre Block, slot, index, provenance et séparation RAW/continuité restent inchangés. Aucun nouvel export, aucune dépendance et aucun scope de `pre.006` n'est ajouté. Gate opérateur à rejouer : ```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 ``` ## 47. Gate opérateur `pre.005-fix.001` Le gate opérateur communiqué pour `0.3.12-pre.5.fix.1` est entièrement vert : ```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, 809 fichiers) cargo check --workspace: PASS cargo clippy --workspace --all-targets --all-features -- -D warnings: PASS cargo test -p ksp-worker-raw-transaction-ingest-lib: PASS 56 unit tests Worker: PASS 6 dependency-boundary tests: PASS 12 hardening tests: PASS 8 public-api tests: PASS 3 release-completeness tests: PASS Doc-tests: PASS ``` Cette base ferme donc `pre.005` et son fix de conversion `YellowstoneTransactionSignature::as_bytes()` avant ouverture de la source productive. ## 48. `pre.006` — source Yellowstone productive `start_with_runtime_resources` ne délègue plus au foundation sans source. Après les validations synchrones Store/settings/runtime-resources déjà qualifiées, il : ```text consomme RawTransactionIngestRuntimeResources extrait exactement une RawTransactionIngestYellowstoneSource clone les settings nécessaires au child privé spawn exactement un child dans le SourceTasks JoinSet existant laisse le supervisor 0.3.11 posséder stop/drain/fault ``` Le child ouvre la session uniquement via : ```text YellowstoneGrpcChannel::open_standard_subscribe SolanaYellowstoneGrpcSubscribeSession::next_update SolanaYellowstoneGrpcSubscribeSession::close ``` Le Worker ne crée aucun `tonic::Channel`, client Geyser, client Reqwest ou actor gRPC parallèle. Transport reste propriétaire des metadata, credentials, ping/pong, message-size bounds et reconnect interne. Le stop privé est prioritaire pendant l'ouverture, pendant la lecture de stream et pendant l'envoi vers l'admission. Un stop avant ouverture abandonne le futur d'ouverture sans session orpheline. À la sortie, les hydrations privées sont abort/join puis la session Transport est fermée via son close borné. ## 49. Routage productif des updates Le dispatch productif est désormais : ```text Transaction -> 1 RawTransactionIngestSourceSignal -> hydration TransactionStatus -> 1 RawTransactionIngestSourceSignal -> hydration Block -> N RawTransactionIngestSourceSignal dans l'ordre source -> hydration BlockMeta -> RawTransactionIngestContinuitySignal continuity-only Slot -> RawTransactionIngestContinuitySignal continuity-only Account/Entry/Ping/Pong -> aucun RAW Worker ``` `BlockMeta` et `Slot` restent délibérément sans admission RAW. `dead_error` et `TransactionStatus.error` ne sont pas lus. Aucun `getBlock`/`get_block_observed` n'est ajouté. Les adapters `pre.003-pre.005`, précédemment gardés sous `#[cfg(test)]` faute de consumer productif, sont maintenant compilés dans le build normal. Le wrapper fixture `hydrate_yellowstone_signal` reste test-only ; la production utilise les deux étapes séparées `fetch_yellowstone_hydration` puis `finalize_yellowstone_hydration`. ## 50. Coalescence bornée d'hydration La clé privée est exactement : ```text network signature commitment ``` Elle ne contient ni family ni filter. Ainsi `Transaction`, `TransactionStatus` et `Block` portant la même signature/network/commitment partagent au plus un `getTransaction` in-flight. Le coordinator privé conserve : ```text BTreeMap JoinSet max_in_flight = persistence_concurrency validée max_pending_signals = MAX_RAW_TRANSACTION_INGEST_ADMISSION_QUEUE_CAPACITY ``` Le nombre de tâches HTTP simultanées est donc borné par le réglage existant de concurrence, sans nouveau knob public. Le nombre de signaux coalescés/pending reste borné par la borne maximale déjà publiée du Worker. Quand cette borne est atteinte, la lecture Yellowstone est backpressurée ; un dépassement à l'intérieur d'une update composite produit un fault source sûr au lieu d'un drop silencieux. À la complétion d'un unique fetch HTTP, chaque signal coalescé est finalisé séparément. Le fan-out reconstruit donc sa propre provenance : ```text transaction_get_transaction status_get_transaction block_get_transaction filter_id direct ou fingerprint propre au signal observed_at propre au signal quand représentable ``` Store idempotence reste ensuite la seconde barrière. Aucun cache de déduplication terminé/non borné n'est conservé. ## 51. Hydration productive et admission Le fetch utilise toujours le contrat `pre.004` : ```text get_transaction_observed encoding = base64 commitment = confirmed | finalized de la source maxSupportedTransactionVersion = 0 ``` Le résultat observé est partagé uniquement entre les signaux ayant la même clé. Chaque finalisation réapplique avant admission : ```text network cohérent route Yellowstone cohérente slot HTTP == slot signal transaction_index cohérent lorsqu'il est présent des deux côtés signature embarquée == signature signal provenance composite sûre depuis le winner HTTP réel ``` `null` reste `Missing` : aucun ingress n'est créé. Une erreur Transport est réduite à son `ErrorCode` KSP sûr. Aucun texte distant n'entre dans l'erreur Worker. Les ingresses disponibles sont envoyés uniquement via le `tokio::sync::mpsc::Sender` déjà créé par `RawTransactionAdmission::new`. Aucun second canal d'admission ou chemin Store n'est introduit. ## 52. Canaris `pre.006` Les nouveaux canaris vérifient au minimum : ```text start_with_runtime_resources -> source.run -> children.spawn open_standard_subscribe/next_update/close présents uniquement via la façade Transport get_transaction_observed reste l'unique hydration HTTP aucun get_block_observed aucun Config/Backfill/backend/reqwest/tonic/proto direct coalescence key = network/signature/commitment Transaction + Status de même signature -> une seule entrée pending et une seule tâche HTTP in-flight signature différente -> clé différente pending et in-flight bornés stop preemptible pendant admission abort_all + join des hydrations privées aucun remote error/dead_error/secret dans la source productive public root inchangé module inventory inchangé ``` ## 53. Non-claims `pre.006` `pre.006` ne prétend pas encore : ```text maintenir une processing frontier interpréter le snapshot reconnect Transport modifier from_slot au niveau Worker interpréter SubscribeReplayInfo prouver une continuité blockchain fault sur gap de rétention prouvé faire un repair/backfill implicite qualifier les races duplicate storm/Store lent finales de pre.009 réussir un smoke provider live sans credentials opérateur ``` Ces responsabilités restent respectivement `pre.007`, `pre.008`, `pre.009` et `pre.011` conformément au plan. ## 54. Gate opérateur requis pour `pre.006` ```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 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 ``` Dans l'environnement d'assemblage, `cargo`, `rustc` et `rustfmt` ne sont pas installés ; aucun gate Cargo local n'est donc revendiqué. ## 55. Gate opérateur `pre.006` et `pre.006-fix.001` Le gate opérateur de `pre.006` confirme : ```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, 810 fichiers) cargo check --workspace : PASS cargo test -p ksp-worker-raw-transaction-ingest-lib : 57 PASS / 1 FAIL ``` Le gate Clippy strict échoue uniquement sur trois `clippy::implicit-return` dans le nouveau chemin productif : la branche neutre du routage Yellowstone et les deux branches de la closure `find_map` qui sélectionne la prochaine hydration non lancée. Le test rouge est `pre_004_source_hydration_rejects_slot_index_signature_and_network_mismatch_before_admission`. La cause n'est pas le test : depuis `pre.006`, le helper de qualification construit la clé et lance le fetch avant d'atteindre le guard réseau de `finalize_yellowstone_hydration`, ce qui transforme le contexte attendu `hydration.network_mismatch` en `hydration.network_key_mismatch`. `pre.006-fix.001` restaure l'invariant plus fort : `hydration_key` rejette immédiatement tout `signal.network != source.network` avec `hydration.network_mismatch`, donc avant coalescence et avant tout HTTP. Le guard de finalisation reste en place comme défense secondaire. Les trois retours implicites sont rendus explicites sans lint neutralisé. La logique de coalescence, les bornes, le fan-out, les provenances et le contrat de stop ne changent pas. ## 56. Gate requis après `pre.006-fix.001` ```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 ``` ## 57. Gate opérateur `pre.006-fix.001` Le gate opérateur communiqué pour `0.3.12-pre.6.fix.1` est entièrement vert : ```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, 811 fichiers) cargo check --workspace : PASS cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS cargo test -p ksp-worker-raw-transaction-ingest-lib : 58 PASS / 0 FAIL ``` Les suites `dependency_boundary`, `hardening`, `public_api`, `release_completeness` et les doc-tests passent également. `pre.006-fix.001` devient donc la base autoritaire de `pre.007`. ## 58. Contrat processing frontier `pre.007` `pre.007` introduit une frontier strictement run-local liée uniquement au travail réellement observé par le source task : ```text source signal Transaction/Status/Block validé -> pending getTransaction -> Missing -> settled getTransaction -> Available + ingress accepté par admission -> settled BlockMeta/Slot continuity-only observé -> settled immédiat ``` `settled` ne signifie ni persisté, ni durable, ni complet sur la blockchain. L'admission queue depth et `in_flight_persistence` restent les métriques séparées qui décrivent les étages aval. La projection publique ajoute uniquement : ```text hydration_pending processing_frontier_slot oldest_pending_slot ``` `processing_frontier_slot` est la plus haute slot réellement observée et settled qui n'est pas située au-delà de la plus ancienne slot pending. Une slot pending bloque donc toujours l'avancement de la frontier. ## 59. Borne mémoire et compaction Le tracker privé conserve les slots pending exactes et compacte les slots settled-only par intervalles autour des slots pending. Il ne conserve qu'un maximum settled par intervalle, plus les slots qui possèdent encore du pending. Avec `N` slots pending distinctes, la représentation reste donc bornée linéairement par le même travail déjà borné par le coordinator d'hydration ; un flux continuity-only sans pending se compacte à une seule slot settled candidate. Aucune map de slots historique/non bornée n'est créée. ## 60. Projection supervisor et activité Le source task publie sa projection par un `tokio::sync::watch` latest-value privé. Le supervisor est l'unique owner du `RawTransactionIngestSnapshotPublisher` et applique la projection dans le snapshot concret existant. La projection peut coalescer des valeurs intermédiaires ; elle ne perd pas de compteur durable car elle ne transporte que des gauges/latest-values calculées à partir de l'état source courant. `WorkerActivity` devient `Active` lorsque `hydration_pending > 0`, même si l'admission queue et les persistences sont momentanément à zéro. Aucune signature, filter, provider, endpoint, transaction/meta ou erreur distante n'entre dans la projection. ## 61. Canaris `pre.007` Les canaris déterministes ajoutés vérifient : ```text frontier initiale vide slot settled 100 -> frontier 100 pending 102 + settled 105 -> frontier reste 100 pending 104 puis settle 102 -> frontier 102, oldest pending 104 settle 104 -> frontier 105 compaction de 0..1000 avec pending 10/20 -> <= 5 états de slot snapshot latest-value hydration_pending/frontier/oldest_pending WorkerActivity active quand hydration_pending > 0 getters publics exacts aucun ReplayInfo/from_slot/continuity_gap/repair aucun backend/Config/Backfill/direct reqwest/tonic/proto ``` ## 62. Non-claims `pre.007` `pre.007` ne prétend pas : ```text interpréter reconnect Transport modifier ou décider from_slot interpréter SubscribeReplayInfo prouver un replay réussi prouver une continuité blockchain maintenir un checkpoint inter-process fault sur gap de rétention lancer un repair/backfill ``` Ces responsabilités restent `pre.008` et les releases de repair ultérieures. ## 63. Gate opérateur requis pour `pre.007` ```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 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 ``` Dans l'environnement d'assemblage, `cargo`, `rustc` et `rustfmt` ne sont pas installés ; aucun gate Cargo local n'est revendiqué. ## 63. Gate opérateur `pre.007` et correctif `pre.007-fix.001` Le gate opérateur de `pre.007` a confirmé les audits Rust/Markdown, puis a révélé un défaut d'intégration purement interne avant exécution des nouveaux tests : ```text processing_frontier_receiver absent de la signature supervise_until_stop processing_frontier_receiver ajouté par erreur au drain admission/persistence deux appels test-only queue_signal encore sur l'ancienne arité ``` Le correctif `pre.007-fix.001` ne modifie pas le contrat de frontier. Il : ```text propage le receiver frontier uniquement vers supervise_until_stop, où il est réellement consommé retire le receiver inutilisé de drain_admission_and_persistence construit un reporter frontier test-only pour les deux appels queue_signal du canari de coalescence ``` Aucune définition pending/settled, compaction, projection snapshot, API publique, source Yellowstone, hydration, admission, persistence, reconnect ou replay n'est modifiée. Les validations Cargo de ce correctif restent à rejouer par l'opérateur. ## 64. Gate opérateur `pre.007-fix.001` et correctif `pre.007-fix.002` Le gate opérateur de `pre.007-fix.001` est vert pour les audits Rust/Markdown, `cargo check`, Clippy strict et les 61 tests unitaires Worker. L'unique échec restant est un canari source de `dependency_boundary` : ```text assertion attendue : 2 tokio::sync::watch::channel dans runtime.rs valeur observée : 3 ``` Cette troisième watch est légitime et appartient à `pre.007` : elle transporte la projection latest-value run-local de processing frontier. Les deux autres watches restent exclusivement les stops external-control et private-source. Le correctif `pre.007-fix.002` ne modifie donc pas le runtime. Il rend le canari structurel exact en vérifiant séparément : ```text 2 x tokio::sync::watch::channel(false) pour les stops 1 x watch de RawTransactionIngestProcessingFrontierProjection::empty() 3 x watch au total dans runtime.rs 1 x watch snapshot concret dans snapshot.rs ``` Aucune définition pending/settled, compaction, projection snapshot, source Yellowstone, hydration, admission, persistence, API publique, reconnect ou replay n'est modifiée. Les validations Cargo de ce correctif restent à rejouer par l'opérateur. ## 65. Gate opérateur `pre.007-fix.002` Le gate opérateur communiqué pour `0.3.12-pre.7.fix.2` est entièrement vert : ```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, 814 fichiers) cargo check --workspace : PASS cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS cargo test -p ksp-worker-raw-transaction-ingest-lib : 61 unit PASS / 0 FAIL dependency_boundary : 8 PASS / 0 FAIL hardening : 14 PASS / 0 FAIL public_api : 9 PASS / 0 FAIL release_completeness : 3 PASS / 0 FAIL doc-tests : 0 FAIL ``` `pre.007-fix.002` devient donc la base autoritaire de `pre.008`. ## 66. Observation reconnect/replay Transport `pre.008` Le moteur Yellowstone Transport possédait déjà la politique de reconnect bornée, la sélection `from_slot`, `SubscribeReplayInfo` et les compteurs conservateurs. `pre.008` n'en duplique aucune partie dans le Worker. Transport ajoute uniquement une façade latest-value clonable et sûre : ```text YellowstoneGrpcSubscribeSnapshotSource current() -> YellowstoneGrpcSubscribeSnapshot wait_for_change() -> Option SolanaYellowstoneGrpcSubscribeSession::snapshot_source() ``` Le `tokio::sync::watch::Receiver` reste privé à Transport. Cloner la source de snapshot ne clone ni le stream gRPC, ni le request state, ni l'actor de reconnect. Un canari Transport vérifie qu'un replay attempt peut être observé pendant `Reconnecting` alors que `reconnect_count == 0`. Le Worker peut donc distinguer : ```text reconnect intent/progress replay-bearing attempt successful reconnect proven retention gap ``` sans inférer ces états à partir des updates métier. ## 67. Projection source-neutral Worker `pre.008` Le Worker étend la même projection latest-value privée déjà utilisée par la processing frontier. Aucun second channel Worker n'est ajouté. Le snapshot concret expose : ```text source_state : Option source_reconnect_total : u64 source_replay_attempt_total : u64 source_continuity_gap_total : u64 ``` `RawTransactionIngestSourceState` est strictement source-neutral : ```text Active Reconnecting Closing Closed Failed ``` La projection ne contient ni signature, filtre, provider, endpoint, payload RAW, `from_slot`, `first_available` ou `ReplayInfo`. Pendant `Reconnecting`, les hydrations HTTP déjà en vol et la processing frontier restent intactes. `WorkerActivity` est `Active` pendant `Reconnecting` ou `Closing`, même si les queues aval sont momentanément vides. ## 68. Politique conservative de gap `pre.008` Le Worker ne fault pas parce qu'un reconnect commence, qu'un replay est tenté ou qu'un `from_slot` est accepté. La seule preuve de discontinuité utilisée est une hausse de : ```text YellowstoneGrpcSubscribeSnapshot::continuity_gap_count() ``` Ce compteur est incrémenté exclusivement par Transport lorsqu'un `SubscribeReplayInfo.first_available` est strictement supérieur à la slot demandée. Cela prouve que la couverture de replay demandée n'est plus entièrement retenue ; cela ne prouve pas qu'un update correspondant au filtre a réellement existé ou a été perdu. Quand ce compteur augmente : ```text projection gap publiée avec les compteurs courants source task -> erreur interne source.continuity_gap_proven supervisor -> ERROR_CODE_RAW_TRANSACTION_INGEST_SOURCE_FAILED Worker -> fault/stop ``` Aucun repair, backfill implicite, `getBlock`, source secondaire ou checkpoint durable n'est déclenché. Les compteurs reconnect/replay/gap observés par le Worker doivent rester monotones ; une régression impossible de snapshot est classée `source.continuity_counter_regression`. ## 69. Ownership replay et non-claims `pre.008` Le Worker ne contient aucun appel à : ```text subscribe_replay_info(...) set_from_slot(...) YellowstoneReplayInfo last_requested_from_slot() ``` Ces primitives restent entièrement dans `ksp-onchain-transport-lib`. En particulier, le Worker ne calcule, ne clamp et ne persiste jamais de `from_slot`. `pre.008` ne prétend pas : ```text qu'un replay accepté est lossless qu'un replay successful prouve la continuité complète faire un repair historique automatique faire un failover multi-provider maintenir un checkpoint inter-process dédupliquer exactement-once transformer processing_frontier en preuve de durabilité ou de complétude blockchain ``` ## 70. Canaris et gate requis pour `pre.008` Les canaris déterministes ajoutés couvrent : ```text watcher Transport latest-value clonable sans fuite Tokio publique replay_attempt_count > 0 possible avant reconnect_count > 0 mapping exact des cinq états source-neutral reconnect/replay/gap counters projetés dans le snapshot Worker processing frontier préservée pendant Reconnecting gap prouvé -> erreur source.continuity_gap_proven régression de compteur -> source.continuity_counter_regression aucun ownership Worker de ReplayInfo/from_slot/repair frontier pre.007 toujours processing-only inventaire public Worker mis à jour exactement redaction de la projection reconnect/replay ``` Gate opérateur requis : ```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-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 ``` Dans l'environnement d'assemblage, `cargo`, `rustc` et `rustfmt` ne sont pas installés ; aucun gate Cargo local n'est revendiqué. ## 71. Gate opérateur `pre.008` et fix `.001` Le gate opérateur de `0.3.12-pre.008` valide : ```text audits Rust/Markdown : PASS cargo check --workspace : PASS cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS ksp-onchain-transport-lib : 388 unit tests PASS, 51 public_api PASS, 43 release_completeness PASS ksp-worker-raw-transaction-ingest-lib : 63 unit tests PASS, 9 dependency_boundary PASS ``` Les smokes réseau Transport restent explicitement `ignored`, conformément à leur politique opérateur. L'unique échec est `pre_010_production_surface_has_no_historical_backfill_or_retriever_contract` dans `hardening`. Le canari interdit volontairement le token `historical` dans toute source production Worker. `pre.008` avait introduit ce mot uniquement dans la documentation de crate : ```text historical repair remains outside this crate ``` Aucun contrat, import, dépendance, type ou appel historique/backfill/retriever n'est présent. Le fix `.001` conserve donc le canari strict inchangé et reformule uniquement cette documentation en : ```text history repair remains outside this crate ``` Le fix ne modifie ni reconnect/replay, ni `from_slot`, ni `ReplayInfo`, ni la processing frontier, ni l'hydration, ni l'admission/persistence, ni l'API publique. ## 72. Gate opérateur `pre.008-fix.001` et fix `.002` Le gate opérateur de `0.3.12-pre.8.fix.1` valide : ```text audits Rust/Markdown : PASS cargo check --workspace : PASS cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS ksp-onchain-transport-lib : 388 unit tests PASS, 51 public_api PASS, 43 release_completeness PASS ksp-worker-raw-transaction-ingest-lib : 63 unit tests PASS, 9 dependency_boundary PASS, 15 hardening PASS ``` L'unique échec restant est `v0_3_12_pre_007_processing_frontier_snapshot_getters_are_public_and_processing_only` dans `public_api`. Le canari `pre.007` interdit volontairement les tokens `ReplayInfo`, `from_slot`, `repair` et `backfill` dans la racine publique Worker. Après le fix `.001`, le seul token `repair` restant dans `src/lib.rs` est encore documentaire : ```text history repair remains outside this crate ``` Aucune API, dépendance ou logique de repair/backfill n'est exposée. Le fix `.002` conserve donc le canari `public_api` inchangé et reformule uniquement cette documentation en : ```text history remediation remains outside this crate ``` Le correctif ne modifie aucun comportement reconnect/replay, aucune ownership de `from_slot`/`ReplayInfo`, aucune processing frontier, hydration, admission, persistence ou API publique. ## 73. Gate opérateur `pre.008-fix.002` Le gate opérateur communiqué pour `0.3.12-pre.8.fix.2` est entièrement vert : ```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, 817 fichiers) cargo check --workspace : PASS cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS ksp-onchain-transport-lib : 388 unit PASS, 51 public_api PASS, 43 release_completeness PASS, doc-tests PASS ksp-worker-raw-transaction-ingest-lib : 63 unit PASS, 9 dependency_boundary PASS, 15 hardening PASS, 9 public_api PASS, 3 release_completeness PASS ``` Les smokes réseau restent `ignored` et operator-only. `pre.008-fix.002` devient la base autoritaire de `pre.009`. ## 74. No-orphan et frontier conservative `pre.009` Le cleanup terminal du source task conserve l'ordre suivant : ```text stop/fault source -> abort_all des hydrations privées -> join de toutes les tâches privées -> clear de la coalescence/pending source -> abandon des pending de processing frontier -> Closing -> close session Transport -> Closed ou Failed ``` L'abandon d'un pending n'est jamais transformé en `settled`. `discard_all_pending` supprime de la frontier toute slot qui possédait encore du travail pending, même si d'autres signaux de cette même slot avaient déjà été settled. La dernière `processing_frontier_slot` publiée reste donc conservative et ne peut pas avancer à travers du travail abandonné pendant stop/fault. Aucun nouvel état public ou compteur n'est ajouté. ## 75. Hardening races/retry/backpressure `pre.009` Les nouveaux canaris déterministes couvrent : ```text duplicate storm bornée par max_pending_signals hydration réellement in-flight -> abort/join puis projection pending nettoyée même network/signature/commitment -> une seule entrée de coalescence saturation -> source.hydration_pending_saturated, aucun drop silencieux abort -> pending_signal_count = 0, map vide, JoinSet vide abort -> hydration_pending = 0 sans faux settlement de la slot abandonnée settle_pending overflow -> aucune mutation partielle du pending/frontier un seul appel Worker get_transaction_observed aucun timer sleep/interval de retry Worker ``` Le retry HTTP reste exclusivement propriété de `ksp-onchain-transport-lib`. Le Worker ne superpose donc aucun retry loop au retry Transport. Les canaris runtime déjà présents depuis le socle `0.3.11` restent les preuves de : ```text Store lent -> backpressure observable sans drop ni admission unbounded source failure -> compteur source_failure et terminal fault stable stop pendant drain -> une erreur Store déjà observée n'est pas masquée drain timeout -> abort/join de tous les source/persistence tasks possédés counter exhaustion snapshot -> ERROR_CODE_RAW_TRANSACTION_INGEST_COUNTER_EXHAUSTED sans wrap ``` Les fixtures hydration existantes restent les preuves de `getTransaction null -> Missing` et des erreurs de validation/hydration terminales sans payload distant. ## 76. Non-claims et gate `pre.009` `pre.009` ne modifie pas : ```text Transport reconnect/from_slot/ReplayInfo politique proven retention gap -> source fault provenance composite format Common RAW Store API/backend processing frontier publique API publique Worker Config ou Backfill ``` Aucun retry missing futur, failover multi-provider, repair automatique, checkpoint durable ou exactly-once n'est introduit. Gate opérateur requis : ```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-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 ``` Dans l'environnement d'assemblage, `cargo`, `rustc` et `rustfmt` ne sont pas installés ; aucun gate Cargo local n'est revendiqué. ## 77. Gate opérateur `pre.009` et correction du canari duplicate-storm Le gate opérateur reçu pour `0.3.12-pre.9` confirme : ```text cargo check --workspace : PASS cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS ksp-onchain-transport-lib : 388 unit PASS, 51 public_api PASS, 43 release_completeness PASS, doc-tests PASS ksp-worker-raw-transaction-ingest-lib : 65/66 unit PASS avant fix ; l'unique échec est le nouveau canari duplicate-storm ``` L'échec est : ```text pre_009_duplicate_storm_is_bounded_coalesced_and_abort_leaves_no_orphan_frontier left: None right: Some(9) ``` La cause est le canari, pas le runtime. La compaction run-local de `pre.007` conserve une représentation bornée des slots settled. Après `observe_settled(10)`, la predecessor `9` peut déjà avoir été compactée ; si un pending tardif arrive ensuite sur `10`, la projection conservative autorisée est donc `None` plutôt qu'une predecessor inventée. `pre.009-fix.001` ne modifie pas la logique productive. Le canari vérifie désormais les invariants réellement garantis : ```text le pending sur 10 ne peut jamais publier frontier = 10 la frontier sûre observée avant abort est mémorisée telle quelle abort_all nettoie pending/coalescence/tasks après abort, la frontier est identique à la frontier sûre pré-abort aucun pending abandonné n'est transformé en settled ``` Ainsi, le test reste strict sur le no-orphan et l'absence d'avancement artificiel, sans exiger une history predecessor que la compaction bornée n'a pas obligation de conserver. Version de fix : ```text workspace.package.version = 0.3.12-pre.9.fix.1 ``` Gate opérateur requis : ```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-onchain-transport-lib cargo test -p ksp-worker-raw-transaction-ingest-lib ```