12 KiB
Delta 0.3.6-pre.005 — fondation Backfill et découverte bornée
Base requise
0.3.6-pre.004 appliquée
workspace.package.version = 0.3.6-pre.4
Le gate opérateur fourni pour cette base confirme :
cargo fmt --all PASS
python3 scripts/audit_rust_workspace_rules.py PASS / clean
python3 scripts/audit_markdown_tables.py ... PASS / clean (264 tables / 146 fichiers)
cargo check --workspace PASS
cargo clippy --workspace --all-targets PASS
cargo test -p ksp-onchain-transport-lib PASS
unitaires 385 PASS
public_api 50 PASS
release_completeness 43 PASS
doctests 4 PASS
cargo tree -p ksp-onchain-transport-lib --edges normal exécuté
cargo tree -p ksp-onchain-transport-lib -e features exécuté
Les smokes réseau restent opt-in et ignorés dans le gate normal, conformément à leur contrat.
Objectif
Matérialiser exclusivement la tranche pre.005 du plan 027 : créer ksp-job-backfill-lib et figer la requête, les scopes, l'identité des candidats, les bornes ainsi que la découverte paginée déterministe avant toute hydratation getTransaction, conversion RAW, persistance Store, checkpoint ou runtime de Job.
Cette tranche résout explicitement un invariant d'identité qui ne doit jamais dépendre de la topologie d'acquisition : une transaction/signature est identifiée logiquement par son réseau et sa signature, pas par le provider, l'endpoint ou le protocole qui l'a retrouvée.
Identité réseau contre provenance Transport
Le contrat de découverte introduit :
BackfillCandidateIdentity = (RawNetworkId, BackfillSignature)
RawNetworkId est un identifiant logique ouvert réexporté par ksp-store-lib. Des namespaces comme mainnet, devnet, testnet, localnet, synthetic ou un futur réseau nommé restent donc distincts sans imposer un enum fermé dans Job.
En conséquence :
- la même signature observée sur deux réseaux différents représente deux identités distinctes ;
- la même signature acquise plusieurs fois sur le même réseau via HTTP, WebSocket ou gRPC converge vers la même identité transactionnelle ;
- rôle Transport, provider, endpoint et protocole décrivent la sélection ou la provenance d'acquisition ; ils ne participent jamais à l'identité transactionnelle ;
JobIdet la future concurrence d'hydratation ne participent pas non plus au fingerprint sémantique d'un scope.
Le Store API possède déjà RawTransactionReference { network, signature }. Le backend PostgreSQL actuel lie en outre un Store physique à un seul RawNetworkId via ksp_store_identity; une clé physique locale basée sur la signature y reste donc dans un namespace réseau unique. Tout futur backend hébergeant plusieurs réseaux dans le même namespace physique devra préserver l'identité logique (network, signature) par sa clé, sa partition ou un mécanisme équivalent.
Crate ksp-job-backfill-lib
La nouvelle crate est une bibliothèque comportementale indépendante, sans exécutable ni Worker. Ses dépendances normales sont limitées à :
ksp-core-lib
ksp-job-api
ksp-logging-lib
ksp-onchain-transport-lib
ksp-store-lib (default-features = false)
sha2 (workspace)
Tokio est uniquement une dev-dependency avec les features de test nécessaires aux canaries async. Aucun backend Store n'est activé par défaut par Backfill.
La crate ne dépend pas directement de Config, Interface, Program, Wallet, Store API, Store PostgreSQL, reqwest, tonic ou d'une crate protocolaire Solana.
Requête bornée
BackfillRequest impose explicitement :
JobId;RawNetworkId;- rôle HTTP Transport ;
- engagement
ConfirmedouFinalized; - un des quatre scopes ;
- page size
1..=1000; - max pages
1..=10000; - max candidates
1..=10000; - future concurrence d'hydratation
1..=64; min_context_slotoptionnel uniquement pour les scopes adresse.
Le rôle HTTP sert uniquement à la sélection Transport. Il est volontairement exclu du fingerprint du scope avec provider, endpoint et protocole.
Scopes
Quatre scopes sont matérialisés :
LatestAddress(address): fenêtre courante depuis le plus récent ;BeforeAddress(address, anchor): historique plus ancien que l'ancre exclusive ;AfterAddress(address, anchor): fenêtre plus récente la plus proche d'une ancre exclusive ;ExplicitSignatures(signatures): liste explicite bornée sans découverte adresse.
Les signatures explicites sont dédupliquées selon la première occurrence et conservent leur ordre d'entrée.
BackfillSignature valide dans cette tranche uniquement la forme texte Base58 bornée compatible avec une signature Solana de 64 octets. Le décodage Base58 exact vers la signature RAW canonique de 64 octets reste volontairement réservé à pre.006; pre.005 ne prétend donc pas encore valider le contenu binaire canonique.
Fingerprint de scope
BackfillScopeFingerprint utilise SHA-256 avec séparation de domaine et couvre les paramètres qui changent réellement la sémantique de découverte :
- réseau ;
- commitment ;
- type de scope ;
- adresse ou liste explicite ;
- direction/ancre ;
- page size ;
- max pages ;
- max candidates ;
min_context_slot.
Il exclut intentionnellement :
JobId;- rôle HTTP ;
- provider ;
- endpoint ;
- protocole ;
- concurrence d'hydratation.
Changer de source d'acquisition ne change donc pas l'identité du scope ni celle des transactions candidates.
Découverte paginée
La voie de production appelle uniquement le wrapper typé existant :
HttpTransportPool::get_signatures_for_address
Aucun client HTTP, retry loop, pacing, cooldown, sélection d'endpoint ou politique fournisseur n'entre dans Job.
Les règles figées sont :
- Latest et Before utilisent le curseur
beforeet conservent l'ordre RPC du plus récent au plus ancien ; - Before démarre avec l'ancre exclusive fournie ;
- After utilise
until = anchor, avance parbeforeet ne conserve que lesmax_candidatesles plus proches de l'ancre parmi les signatures plus récentes ; - la déduplication est stable entre pages ;
- une page fournisseur plus grande que la limite demandée est rejetée ;
- un curseur qui n'avance pas est rejeté ;
- une page courte ou vide matérialise
RpcBoundary; - atteindre la limite de candidats matérialise
CandidateLimit; - épuiser
max_pagesen Latest/Before matérialisePageLimitet un résultat partiel ; - épuiser
max_pagesen After avant preuve de la frontière matérialiseAfterAnchorNotReachedet un résultat partiel.
La borne After est volontairement conservative : un Job ne prétend jamais avoir rejoint l'ancre si la limite de pages empêche de le prouver.
Tests matérialisés
La tranche ajoute 11 tests unitaires :
- validation et redaction de signature ;
- déduplication explicite stable ;
- bornes exactes de requête ;
- fingerprint indépendant de JobId/rôle/concurrence mais distinct par réseau ;
- distinction sémantique Before/After ;
- Latest paginé avec déduplication inter-pages ;
- Before avec ancre exclusive et progression du curseur ;
- After avec fenêtre la plus proche de l'ancre ;
- After borné partiel ;
- Latest borné partiel ;
- explicite sans appel Transport et avec identité réseau.
Elle ajoute 6 canaries d'intégration :
- deux canaries de dépendances/firewalls ;
- deux canaries d'API publique, dont l'identité
(network, signature); - deux canaries de complétude qui empêchent l'ouverture anticipée de RAW/persistance/checkpoint/runtime.
Les doubles de page sont privés aux unit tests ; aucune abstraction fake n'entre dans l'API publique.
Documentation courante réconciliée
Les documents d'architecture actifs sont alignés avec le nom désormais matérialisé ksp-job-backfill-lib et son graphe réel sans Config :
docs/architecture/004-COMPONENT_INVENTORY.md
docs/architecture/005-DEPENDENCY_GRAPH.md
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
Les anciens plans historiques ne sont pas réécrits. README, USAGE, CHANGELOG et ROADMAP restent fermés jusqu'aux tranches prévues de réconciliation/fermeture.
Fichiers ajoutés
crates/ksp-job-backfill-lib/Cargo.toml
crates/ksp-job-backfill-lib/src/constants.rs
crates/ksp-job-backfill-lib/src/discovery.rs
crates/ksp-job-backfill-lib/src/error.rs
crates/ksp-job-backfill-lib/src/lib.rs
crates/ksp-job-backfill-lib/src/request.rs
crates/ksp-job-backfill-lib/tests/dependency_boundary.rs
crates/ksp-job-backfill-lib/tests/public_api.rs
crates/ksp-job-backfill-lib/tests/release_completeness.rs
crates/ksp-job-backfill-lib/unit_tests/discovery.rs
crates/ksp-job-backfill-lib/unit_tests/request.rs
deltas/0.3.6/pre.005.md
Fichiers modifiés
Cargo.toml
docs/architecture/004-COMPONENT_INVENTORY.md
docs/architecture/005-DEPENDENCY_GRAPH.md
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md
docs/validation/023-V0_3_6_JOB_API_BACKFILL.md
Mécanique Cargo :
header version: 399 -> 400
workspace.package.version: 0.3.6-pre.4 -> 0.3.6-pre.5
workspace members: + crates/ksp-job-backfill-lib
workspace dependencies versionnées: inchangées
Fichiers supprimés
Aucun.
Frontières conservées
- aucun code kbot3 n'est copié ; kbot3 reste uniquement une référence fonctionnelle ;
- aucune hydratation
getTransactionn'est encore implémentée dans Job ; - aucune conversion RAW v1 n'est ouverte ;
- aucune écriture Store, observation d'acquisition ou politique
ForceRehydraten'est ouverte ; - aucun checkpoint, frontier contiguë, runtime Job ou notification concrète n'est ouvert ;
- aucune lecture Config/env n'est introduite ;
- aucun endpoint/provider/protocole ne devient une clé transactionnelle ;
- aucun backend Store n'est imposé ;
- aucun README/USAGE/CHANGELOG/ROADMAP n'est rouvert.
Validations exécutées dans l'environnement d'assemblage
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/0.3.6
-> Markdown table audit: clean (264 tables / 147 fichiers, présent delta inclus)
python3 -m unittest scripts/tests/test_audit_markdown_tables.py
-> 5 tests / OK
Le premier audit Markdown après réconciliation de l'inventaire a détecté uniquement l'élargissement mécanique requis par ksp-job-backfill-lib; la table a été réalignée sur le contenu le plus large avant le second passage propre.
L'environnement d'assemblage ne fournit ni cargo, ni rustc, ni rustfmt. Les 11 unitaires et 6 canaries Rust sont matérialisés mais ne sont pas annoncés comme exécutés localement.
Gate opérateur demandé
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/0.3.6
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-job-backfill-lib
cargo tree -p ksp-job-backfill-lib --edges normal
cargo tree -p ksp-job-backfill-lib -e features
Le gate doit notamment confirmer :
- 11 unitaires + 6 canaries ;
ksp-store-libsans activation implicite du backend PostgreSQL ;- aucun accès direct à Store API/backend, Config ou dépendance protocolaire ;
- pagination Latest/Before/After et explicite déterministe ;
- résultat partiel conservateur aux bornes ;
- identité candidate scellée par réseau + signature, indépendamment du rôle/provider/endpoint/protocole.
Questions ouvertes
Aucune question ne bloque pre.006 après un gate opérateur vert de pre.005.