# Delta 0.3.13-pre.002 — runtime resources multi-source bornées ## Base requise ```text delivery précédente : 0.3.13-pre.001 Cargo base : 0.3.13-pre.1 delta base : deltas/0.3.13/pre.001.md archive delta base : ksp-general-0.3.13-pre.001.zip SHA-256 delta base : ca57546f19bd47b5d3b832a51905159497a5e601c186460db22b04364a1835c4 ``` Le gate opérateur fourni après application de `pre.001` est vert : fmt, audits Rust/Markdown, check workspace, Clippy strict, tests Worker, arbres normal/features et duplicates ont été exécutés sans anomalie signalée. ## Objectif Matérialiser le contrat `pre.002` défini par le plan `034` sans démarrer prématurément les nouvelles familles live : ```text collection runtime privée bornée 1..32 identité logique déterministe par source source discriminant capability-owned validation globale avant spawn rejet des doublons logiques rejet cross-network aucun nouveau client réseau aucune nouvelle dépendance ``` Le supervisor simultané appartient toujours à `pre.007`. ## Type de livraison ```text 0.3.13-pre.002 Cargo : 0.3.13-pre.2 archive : ksp-general-0.3.13-pre.002.zip ``` ## Runtime resources multi-source `RawTransactionIngestRuntimeResources` ne contient plus directement un unique champ Yellowstone. Il possède désormais une collection privée : ```text Vec ``` Le discriminant privé initial est : ```text Yellowstone(RawTransactionIngestYellowstoneSource) ``` Il est volontairement capability-owned ; aucun provider n'entre dans l'enum Worker. Surface publique ajoutée : ```text MAX_RAW_TRANSACTION_INGEST_LIVE_SOURCES = 32 RawTransactionIngestRuntimeResources::source_count() RawTransactionIngestRuntimeResources::try_push_yellowstone_source(...) ``` `try_push_yellowstone_source` est transactionnel : le candidat est entièrement rejeté sans mutation de la collection si la borne, le réseau ou l'identité logique sont invalides. ## Identité logique Yellowstone Chaque `RawTransactionIngestYellowstoneSource` possède maintenant un `source_key: [u8; 32]` privé. Le hash SHA-256 est dérivé uniquement de données sûres : ```text KSP domain separator source family = yellowstone network provider identity sûre endpoint identity sûre commitment identité opaque de YellowstoneSubscribeRequest ``` Le rôle et le pool HTTP d'hydration sont volontairement exclus du `source_key` : ils ne définissent pas une nouvelle source live Yellowstone. Ainsi, deux subscriptions identiques ne deviennent pas artificiellement distinctes par simple changement de stratégie d'hydration. Sont explicitement absents du matériau en clair et de Debug : ```text URL API key / credential header transaction payload remote error material request identity bytes source_key bytes/hash ``` Concernant `source_key`, le Debug de la source n'en publie que la longueur ; ses autres champs Debug restent les identités sûres déjà admises par le contrat stable. Le Debug de l'aggregate runtime publie seulement `source_count`. ## Identité déterministe de SubscribeRequest dans Transport `ksp-onchain-transport-lib` expose `YellowstoneSubscribeRequestIdentity` comme valeur opaque et `YellowstoneSubscribeRequest::identity()`. Canonicalisation de l'identité : ```text sept familles de filtres séparées ordre déterministe fourni par les BTreeMap KSP nom de filtre length-framed protobuf exact de chaque filtre length-framed options communes protobuf encodées après vidage des sept maps ``` Les bytes internes restent privés. L'identité implémente `Hash` afin que le Worker puisse l'incorporer à son SHA-256 sans escape hatch de sérialisation. Aucune dépendance n'est ajoutée : le codage réutilise `prost` réexporté par `yellowstone-grpc-proto`, déjà dépendance de Transport. ## Validation globale avant spawn Avant activation, `RawTransactionIngestRuntimeResources::validate_network` impose : ```text collection non vide source_count <= 32 chaque source sur le réseau Worker source_key unique dans la collection ``` Les erreurs restent mappées sur le contrat stable `ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID` avec conditions internes stables, sans valeurs sensibles. ## Gate volontaire d'activation multi-source Le plan final exige que toutes les sources configurées soient démarrées simultanément. Cette responsabilité est explicitement réservée à `pre.007`. Pour éviter un comportement faux en `pre.002` : ```text 1 source Yellowstone : voie productive stable conservée 2..32 sources : composition/validation possible start avec 2..32 sources : fail closed avant spawn jamais de démarrage silencieux de la première source seulement ``` Condition interne : ```text runtime_resources.multi_source_activation_pending ``` Ce gate sera supprimé uniquement par la tranche supervisor/source inventory. ## Preuves déterministes ajoutées Transport : ```text identité de request stable malgré ordre d'insertion identité différente si le filtre logique change Debug identité redacted surface identité disponible depuis crate root aucun bytes()/as_bytes() public ``` Worker : ```text source_key stable pour identité logique identique source_key sensible au request fingerprint source_key sensible à l'endpoint identity sûre 32 sources exactement acceptées 33e rejetée sans mutation duplicate source identity rejetée source cross-network rejetée Debug aggregate limité à source_count activation multi-source fail-closed avant pre.007 public API canary pour bound/count/push release export inventory mis à jour ``` ## Compatibilité et non-régression La construction historique : ```text RawTransactionIngestRuntimeResources::new(yellowstone_source) ``` reste valide et crée un aggregate d'une source. La voie productive stable `start_with_runtime_resources` continue donc à fonctionner pour une seule source Yellowstone sans changement de Common RAW, Store, Config ni protocole réseau. ## Fichiers ajoutés ```text deltas/0.3.13/pre.002.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-onchain-transport-lib/src/grpc_subscribe.rs crates/ksp-onchain-transport-lib/src/lib.rs crates/ksp-onchain-transport-lib/tests/public_api.rs crates/ksp-onchain-transport-lib/tests/release_completeness.rs crates/ksp-onchain-transport-lib/unit_tests/grpc_subscribe.rs crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs crates/ksp-worker-raw-transaction-ingest-lib/src/runtime.rs crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.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/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 supprimés ```text aucun ``` ## Versions de fichiers incrémentées ```text grpc_subscribe.rs transport src : 8 -> 9 transport lib.rs : 46 -> 47 transport public_api.rs : 51 -> 52 transport release_completeness.rs : 43 -> 44 transport unit grpc_subscribe.rs : 5 -> 6 worker lib.rs : 17 -> 18 worker runtime.rs : 11 -> 12 worker runtime_resources.rs : 12 -> 13 worker public_api.rs : 11 -> 12 worker release_completeness.rs : 9 -> 10 worker unit runtime_resources.rs : 11 -> 12 plan 034 : 1 -> 2 validation 030 : 1 -> 2 ``` ## Audit intermédiaire et corrections La première passe statique après introduction de l'identité Transport a détecté une rustdoc devenue non adjacente au `YellowstoneSubscribeRequest`. La structure documentaire a été corrigée avant poursuite. Une passe ultérieure après ajout des canaris externes a détecté uniquement : ```text 2 fins de fichier avec newline supplémentaire 1 double ligne vide entre items Rust ``` Ces trois écarts de format ont été corrigés avant la validation finale. Aucun état intermédiaire en échec n'est présenté comme PASS. ## Validations exécutées localement après correction finale ```text python3 scripts/audit_rust_workspace_rules.py PASS : General Rust rule audit clean PASS : Rust export completeness audit 0 candidate PASS : KSP workspace Rust rule audit clean python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas PASS : Markdown table audit clean (340 tables, 829 files) supplemental normative definition-id scan PASS : 489 definitions, 489 unique, 0 duplicate definition id pre-packaging exhaustive diff scan PASS : 14 fichiers modifiés, 1 ajouté, 0 supprimé PASS : chaque header de version des 13 fichiers versionnés modifiés est incrémenté exactement de +1 PASS : aucune nouvelle occurrence de unsafe/unwrap/expect/panic/todo/unimplemented dans les lignes Rust production ajoutées ``` Les caches Python recréés par les scripts d'audit sont supprimés après la dernière passe et ne font pas partie de la livraison. L'archive delta est ensuite contrôlée par inventaire exact, test ZIP et scan des chemins/artefacts. ## Validations non exécutées localement Le toolchain Rust n'est pas installé dans l'environnement d'assemblage courant : ```text cargo fmt --all -- --check 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 ``` Statut : `NON EXÉCUTÉ LOCAL`, jamais PASS. ## Décisions prises ```text conserver 1..32 comme borne runtime P0 source identity opaque et non publique côté Worker faire posséder l'identité exacte SubscribeRequest par Transport ne pas ajouter prost comme dépendance Worker/Transport supplémentaire valider toutes les sources avant spawn rejeter duplicate identity et cross-network avant mutation fail closed pour activation >1 jusqu'à pre.007 ne pas démarrer un sous-ensemble silencieux ne modifier ni Common RAW ni Store API ``` ## Questions ouvertes Aucune nouvelle question bloquante pour `pre.003`. Restent volontairement dans leurs tranches prévues : ```text logsSubscribe standard + hydration : pre.003 blockSubscribe standard : pre.004 Helius transactionSubscribe : pre.005 HTTP polling : pre.006 supervisor simultané / source inventory : pre.007 convergence globale / observations multiples : pre.008 ```