39 KiB
Plan v0.3.6 — Job API et premier backfill RAW
1. But de la version
La v0.3.6 ouvre la famille des Jobs avec deux crates et un premier vertical réel :
ksp-job-api, contrat public passif et runtime-neutral de cycle de vie, annulation et observation latest-value ;ksp-job-backfill-lib, orchestration concrète d'un backfill historique borné ;- découverte par
getSignaturesForAddress, hydratation pargetTransaction, conversion RAW déterministe et persistance parksp-store-lib; - preuve de progression, annulation coopérative, reprise par frontière contiguë et idempotence logique.
Cette version ne crée ni Worker API, ni application, ni scheduler général, ni pipeline RAW partagé prématuré.
2. Audit préalable et hiérarchie des sources
L'audit pre.001 a été conduit avant toute création de crate. Les archives source et de référence ont été testées intégralement, puis extraites dans des arbres séparés. Les règles canoniques du dépôt priment sur les chemins abrégés du prompt : les fichiers effectivement présents sous docs/rules/ sont les autorités applicables.
Sources lues :
RULES.md,docs/000-README.mdet les règles sousdocs/rules/;docs/architecture/002-LAYERS_AND_DEPENDENCIES.mdà005-PERSISTENCE_ARCHITECTURE.md, puis009-JOB_AND_WORKER_ARCHITECTURE.md;ROADMAP.md,CHANGELOG.mdet les deltas antérieurs ;- surfaces Rust réelles de Core, Transport et Store ;
- documentation RPC officielle Solana pour
getSignaturesForAddressetgetTransaction; - kbot3 v0.5.3-pre.005-fix010, uniquement comme inventaire fonctionnel et corpus de scénarios.
Constats structurants :
- le dépôt est stable en v0.3.5 et ne contient encore aucune crate Job ;
- les documents historiques emploient encore parfois
ksp-job-backfill, alors que le nom canonique fixé par le prompt estksp-job-backfill-lib; ksp-onchain-transport-libfournit déjà les deux wrappers typés, le routage, les délais, la limitation et les retries ;- le retour de
getTransactionne transporte pas encore l'identité de l'endpoint réellement retenu, alors que la provenance Store exige au minimum un fournisseur ; ksp-store-libréexporte le contrat Store, fournit l'écriture atomique transaction plus observation et doit rester l'unique accès Job au Store ;- aucune règle n'autorise une réutilisation de code kbot3. Aucun fichier, extrait ou algorithme n'est copié depuis cette archive.
3. Périmètre retenu et non-objectifs
Dans le périmètre :
- identifiants et états de Job ;
- source d'observation multi-listeners à valeur la plus récente ;
- token d'annulation indépendant de Tokio ;
- quatre portées de backfill : dernière fenêtre d'une adresse, avant une ancre, après une ancre et signatures explicites ;
- pagination bornée, déduplication stable, hydratation bornée et persistance RAW ;
- résultat observable, compteurs structurés, checkpoint et frontière contiguë ;
- tests unitaires, dépendances interdites, canaries externes et intégration déterministe.
Hors périmètre :
ksp-worker-api, application desktop, CLI, configuration utilisateur et ordonnanceur ;- décodage métier des transactions, normalisation SPL ou indexation sémantique ;
- journal persistant des tentatives RPC manquantes ou échouées ;
- callbacks producteurs, file de notifications non bornée et historique public complet ;
- retry, pacing, sélection d'endpoint ou requête HTTP parallèles au Transport ;
- backend Store direct,
ForceRehydrateet prélecture de présence avant hydratation ; - extraction d'une crate pipeline partagée avant l'arrivée d'un second hôte réel.
4. Matrice de décision kbot3
Le tableau décrit des comportements observés ; il ne constitue pas une filiation de code.
| Fonction historique | Preuve fichier, test ou run | Sémantique réelle | Statut KSP | Owner KSP cible | Risque ou différence actuelle | Préversion cible |
|---|---|---|---|---|---|---|
| Sources latest, before et after | ks-pipeline/src/backfill.rs, collect_before_candidates, collect_after_candidates |
Pagination d'adresse, ancre exclusive et fenêtre plus récente proche | REPRENDRE | Backfill avec wrappers Transport | L'ordre after doit être figé et l'ancre non atteinte observable | pre.005, pre.008 |
| Signatures explicites | explicit_candidates_are_deduplicated_in_input_order |
Première occurrence conservée et ordre d'entrée stable | REPRENDRE | Backfill | Validation Base58 et limite absentes du type KSP actuel | pre.005 |
| Déduplication inter-pages | nearest_newer_candidates_deduplicate_page_entries |
Un candidat identique n'est admis qu'une fois | REPRENDRE | Backfill | Doit couvrir toutes les directions, pas seulement after | pre.005 |
| Fenêtre after la plus proche | nearest_newer_candidates_keep_only_entries_closest_to_anchor |
Retient les N signatures plus récentes les plus proches de l'ancre | REPRENDRE | Backfill | Nécessite une preuve officielle et un ordre KSP déterministe | pre.005 |
| Frontière contiguë | completion_frontier_advances_only_across_contiguous_results |
Une fin hors ordre ne saute pas un candidat incomplet | REPRENDRE | Backfill | Missing et erreurs ne doivent pas être marqués durables | pre.008 |
| Reprise before | cancelled_before_resume_uses_last_contiguous_candidate, cancelled_before_resume_keeps_anchor_when_nothing_completed |
Curseur repris au dernier préfixe contigu ou à l'ancre initiale | REPRENDRE | Backfill et hôte pour garde durable | Le checkpoint doit être lié au JobId et au scope | pre.008 |
| Reprise latest | cancelled_latest_scan_without_completed_candidate_restarts_from_latest |
Une vue latest vide de complétion repart sans curseur | REPRENDRE | Backfill | Le replay doit dépendre de l'idempotence Store | pre.008 |
| Annulation d'attente et RPC long | cancellable_retry_wait_returns_immediately_when_already_cancelled, long_running_rpc_future_is_cancelled_cooperatively |
Une sélection coopérative abandonne le futur non durable | REPRENDRE | Job API pour token, Backfill pour runtime | Un commit Store soumis ne peut pas être abandonné aveuglément | pre.002, pre.009 |
| Taxonomie Program, Token ou Pool | BackfillAddressKind, filter_code_distinguishes_target_and_direction |
Étiquette UI intégrée au filtre historique | REDESSINER | Application v0.3.7 | Une adresse Core ne porte pas ce domaine de présentation | v0.3.7 |
Callback BackfillObserver |
ks-pipeline/src/backfill.rs, DemoBackfillObserver dans l'application |
Le producteur appelle directement un consumer et émet un message | REDESSINER | Job API et snapshot concret Backfill | Blocage, panic consumer et chaînes humaines possibles | pre.003, pre.009 |
Compteurs existing_skipped, canonical_skipped, missing, failed |
BackfillSummary et summary_payload |
Plusieurs résultats Store ou RPC sont agrégés avec ambiguïtés | REDESSINER | Backfill snapshot | KSP doit distinguer entité, observation, purge, missing et conflit | pre.007, pre.009 |
| Prélecture Store avant hydratation | hydrate_candidate, branche existing_skipped |
Une signature connue saute l'acquisition et l'observation | REJETER | Aucun | Course TOCTOU, purge et acquisition nouvelle perdues | Aucun |
| Retry, pause et parsing texte | retry_delay_ms, wait_with_cancellation, branches HTTP 429 et timeout |
Le Job rythme et retente selon des chaînes d'erreur | REJETER | Transport exclusivement | Amplification des retries et contrat d'erreur instable | Aucun |
| Persistance missing ou failed | persist_missing_observation, persist_failed_observation |
Une tentative sans transaction canonique devient observation durable | REPORTER | Futur contrat Store de journal d'acquisition | RawTransactionObservation KSP exige aujourd'hui une transaction complète |
Version ultérieure |
| Reprise durable multi-processus | Résumé resume_before_signature et application demo |
Le caller reçoit une ancre, sans contrat de garde durable KSP | REPORTER | Application ou scheduler futur | Aucune propriété de persistance de checkpoint n'existe en v0.3.6 | Version ultérieure |
5. Ownership par couche
| Sujet | Propriétaire | Contrat |
|---|---|---|
| Identité, état et annulation d'un Job | ksp-job-api |
Types publics runtime-neutral et sans effet de bord |
| Snapshot concret du backfill | ksp-job-backfill-lib |
Phase, progression, checkpoint et résultat sûrs |
| Pagination et hydratation Solana | ksp-onchain-transport-lib |
Wrappers RPC typés existants |
| Routage, pacing, retry et délai | ksp-onchain-transport-lib |
Aucune boucle concurrente dans Job |
| Conversion en RAW canonique | ksp-job-backfill-lib |
Adaptateur concret du premier vertical |
| Idempotence, conflit et purge | ksp-store-lib |
Écriture atomique en mode Normal |
| Logs internes | ksp-logging-lib |
Champs sûrs, pas de secret ni réponse brute |
| Configuration et supervision | Application v0.3.7 | Pas de dépendance Config en v0.3.6 |
6. Contrat public de ksp-job-api
La crate reste passive et ne dépend que de ksp-core-lib si un type fondamental existant est requis. Elle n'expose ni Tokio, ni Transport, ni Store, ni Logging, ni serde dans sa surface publique.
Types prévus :
JobId, identifiant borné, validé et fourni par l'hôte afin de rester stable pendant une reprise ;JobKindCode, code stable et borné sans texte humain libre ;JobState:Created,Running,Cancelling,Completed,CancelledouFailed;JobCompletion:CompleteouPartial, le second signalant des trous attendus comme une transaction RPC absente ;JobNotificationSequence, compteur strictement croissant vérifié ;JobNotification<S>, enveloppe générique contenant l'identité, la séquence, l'état et le snapshot le plus récent ;JobSnapshotSource, trait à type associé fournissant la valeur courante et une attente abstraite d'un changement après une séquence ;JobCancellationToken, cloneable, idempotent et fondé sur des primitivesstd.
Le contrat ne contient pas de booléen redondant avec JobState, pas de message humain, pas de timestamp mural dont l'ownership serait ambigu et pas de méthode spawn.
La surface concrète du backfill accepte BackfillRequest, HttpTransportPool et un Arc<Store>. Sa construction rend un exécuteur possédé et un BackfillJobHandle cloneable ; l'hôte décide où exécuter la future run, tandis que le handle fournit annulation et observation. Les ports étroits employés par le moteur restent privés et servent aux doubles déterministes internes ; l'API publique ne duplique pas les contrats Transport ou Store.
7. Notifications latest-value multi-listeners
Audit des formes candidates avant choix :
| Forme | Runtime-neutralité API | Backpressure | Multi-listener | Livraison terminale | Resynchronisation | Testabilité | Réutilisation Worker future |
|---|---|---|---|---|---|---|---|
| Polling snapshot par caller | Forte | Naturellement bornée | Oui | Oui si le caller repolle | Snapshot direct | Simple mais latence artificielle | Possible, coûteux si polling serré |
| Callback ou sink | Moyenne | Le producer peut bloquer | Composition manuelle | Fragile sur panic ou abandon | Aucune native | Courses et réentrance difficiles | Rejetée |
| Watch ou latest-value | Forte avec futur abstrait | O(1), coalescence explicite | Oui | Oui, valeur retenue | Snapshot complet courant | Déterministe avec séquences | Bon motif, contrat Worker distinct plus tard |
| Broadcast ou fan-out | Faible si primitive runtime publique | Lag ou pertes par consumer | Oui | Dépend du buffer et de l'abonnement | Besoin d'un snapshot parallèle | Sensible aux buffers | Ne pas imposer avant Worker API |
| File bornée | Moyenne | Blocage ou drop à définir | Non sans fan-out supplémentaire | Peut être coincée derrière la progression | Replay limité au buffer | Nombreuses politiques périphériques | Trop lourde pour le besoin actuel |
Le choix est watch ou latest-value avec séquence et snapshot complet. Il conserve l'observabilité sans imposer la primitive d'un runtime à ksp-job-api.
Le modèle public est une valeur la plus récente, non une file d'événements :
- le producteur remplace un unique snapshot en mémoire en O(1) ;
- chaque listener conserve sa dernière séquence et demande la valeur courante ou attend une séquence supérieure ;
- un listener lent peut coalescer des progressions intermédiaires, mais reçoit toujours l'état courant complet ;
- plusieurs listeners ne se bloquent pas mutuellement et n'exécutent jamais de code dans le producteur ;
- l'état terminal reste lisible tant que le handle partagé existe ;
- une séquence manquée provoque une resynchronisation par snapshot complet, pas une erreur de replay ;
- l'échec d'un listener et son abandon n'affectent pas le Job ;
- aucune donnée brute RPC, URL, secret, signature en masse ou erreur fournisseur libre n'est publique.
L'implémentation Tokio de réveil reste privée à ksp-job-backfill-lib. Le trait de l'API retourne un futur abstrait appartenant à la crate, sans type Tokio public.
8. Requête et portées du backfill
BackfillRequest exige tous les paramètres opérationnels ; la bibliothèque ne choisit pas silencieusement des valeurs d'application.
Champs communs :
JobId, réseau Store attendu, rôle HTTP, engagementConfirmedouFinalized;- taille de page de 1 à 1 000 ;
- nombre maximal de pages de 1 à 10 000 ;
- limite maximale de 10 000 candidats par Job ;
- concurrence d'hydratation de 1 à 64 ;
min_context_slotoptionnel pour les portées adresse ;- scope et checkpoint optionnel validé contre l'identité du scope.
Portées :
LatestAddress: adresse, sans ancre, retourne les signatures les plus récentes dans l'ordre RPC ;BeforeAddress: adresse et ancre exclusive, remonte vers les signatures plus anciennes ;AfterAddress: adresse et ancre exclusive, collecte la fenêtre plus récente la plus proche de l'ancre ;ExplicitSignatures: liste non vide de signatures validées et bornées.
Le fingerprint de scope couvre réseau, adresse ou digest de liste, direction, ancre, engagement et limites sémantiques. Une reprise avec un checkpoint d'un autre scope est rejetée à l'admission.
9. Sémantique RPC officielle figée
| Appel | Configuration retenue | Sémantique consommée |
|---|---|---|
getSignaturesForAddress |
engagement, before, until, limit, minContextSlot |
Résultats du plus récent au plus ancien ; ancres exclusives |
getTransaction |
engagement, encodage base64, version maximale 0 |
Transaction confirmée ou null, avec slot, block time, transaction, meta et version |
Références officielles :
- https://solana.com/docs/rpc/http/getsignaturesforaddress
- https://solana.com/docs/rpc/http/gettransaction
Décisions :
LatestAddressetBeforeAddresssuivent directement l'ordre de page officiel ;AfterAddressutiliseuntilpour rechercher l'ancre, conserve les candidats strictement plus récents et sélectionne les plus proches de l'ancre dans un ordre historique déterministe ;- une ancre
BeforeAddressabsente des pages n'est pas une erreur car elle sert de curseur RPC ; - une ancre
AfterAddressnon atteinte dans la borne de pages est un résultat partiel observable et ne produit aucun checkpoint au-delà du trou ; - les doublons inter-pages et intra-requête sont retirés à première occurrence sans réordonner arbitrairement ;
getTransaction = nulldevientMissing, sans écriture Store et sans fabrication de provenance.
10. Format RAW v1 et conversion
Le premier format concret est ksp.solana.raw_transaction, version 1.
Acquisition :
getTransactionest demandé enbase64avecmaxSupportedTransactionVersion = 0;- les encodages
jsonParsedet toute structure interprétée par un fournisseur sont refusés ; - la signature Base58 est décodée vers exactement 64 octets sans introduire le SDK Solana complet ;
- un
blockTimenégatif, impossible à représenter parRawTimestamp, est une erreur de conversion terminale et n'est jamais supprimé silencieusement.
Payload canonique :
- UTF-8 JSON compact produit par un sérialiseur déterministe appartenant au backfill ;
- jeu et ordre de clés figés par tests ;
- transaction binaire conservée comme tuple base64 plus marqueur d'encodage ;
meta,versionettransactionIndexconservent la distinction champ absent,nullet valeur ;- le slot et le block time sont portés par
RawTransactionet ne sont pas dupliqués dans les bytes ; - hash SHA-256 et taille sont calculés sur les bytes canoniques exacts avant construction de
RawPayload.
Toute évolution de version de transaction supportée ou du format impose une nouvelle version de payload et des canaries de compatibilité.
11. Extension Transport minimale pour la provenance
Le wrapper typé actuel perd l'identité de l'endpoint finalement utilisé après routage ou retry. La v0.3.6 ajoute une voie additive observée pour getTransaction :
- elle réutilise exactement la même admission, la même sélection, les mêmes retries et le même décodage ;
- elle retourne la valeur typée accompagnée d'un identifiant sûr de fournisseur et d'endpoint effectivement victorieux ;
- elle n'expose ni URL, ni en-tête, ni body brut ;
- l'API existante reste compatible et peut continuer à ne retourner que la valeur ;
- les tests prouvent qu'un reroutage rapporte l'endpoint final, pas le candidat initial.
Cette extension ne crée pas un second client RPC et ne déplace aucune politique vers Job.
12. Provenance, observation et identité
Chaque transaction disponible produit :
- une
RawTransactionReferencecomposée du réseau et de la signature 64 octets ; - une
RawTransactioncomplète et canonique ; - une
RawAcquisitionProvenanceavec fournisseur, protocole Solana HTTP JSON-RPC, méthodegetTransaction, endpoint sûr, engagement, instant de réception etJobIdcomme session de capture ; - une
RawTransactionObservationdont la clé déterministe est un SHA-256 domain-separated duJobId, du fingerprint de scope, de la signature, du fournisseur, de l'endpoint, de l'engagement et de la version du contrat d'acquisition.
Une reprise du même Job par le même endpoint retrouve donc l'observation. Un autre endpoint constitue une nouvelle acquisition légitime. Une différence de payload canonique pour la même référence reste un conflit Store, jamais un skip.
13. Persistance et idempotence
Le Job appelle uniquement ksp-store-lib::persist_raw_transaction_acquisition en mode Normal.
Sont distingués dans les compteurs :
- entité
Inserted,AlreadyPresentouSkippedPurged; - observation
Inserted,AlreadyPresentouNotRecorded; - transaction RPC
Missing; - conflit, conversion invalide, erreur Transport et erreur Store.
Il n'existe pas de prélecture has avant hydratation. Une relance avec le même JobId et le même scope est logiquement idempotente : l'entité n'est pas dupliquée, l'observation identique est déjà présente et les différences réelles restent visibles.
Les tentatives sans transaction canonique restent dans le résultat runtime. Leur journalisation persistante est reportée à un contrat Store ultérieur explicite.
14. Ordonnancement, bornes et backpressure
Le Job sépare trois étapes : découverte, hydratation, persistance.
- découverte paginée séquentielle afin de préserver les ancres et l'ordre ;
- collection bornée à 10 000 candidats et déduplication stable ;
- au plus 64 hydratations en vol, limitées par la requête ;
- une persistance par candidat hydraté, sans file non bornée ;
- admissions arrêtées dès annulation ou erreur fatale ;
- fin des opérations Store déjà soumises avant publication de l'état terminal afin de ne jamais ignorer un commit possible ;
- compteurs
u64mis à jour par opérations vérifiées, un overflow devenant une violation d'invariant sûre et non un panic.
Le débit externe reste gouverné par le pool Transport. Ajouter une temporisation Job serait une amplification de politique interdite.
15. Frontière contiguë et checkpoint
Chaque candidat reçoit un index stable après déduplication. Le checkpoint ne progresse que sur le préfixe contigu des résultats durables suivants :
- entité insérée ;
- entité déjà présente avec contenu identique ;
- entité purgée et correctement sautée par la politique Store normale.
Missing, conflit, erreur de conversion, erreur Transport, erreur Store ou annulation créent un trou. Des candidats ultérieurs peuvent terminer, mais la frontière ne saute jamais ce trou.
Le checkpoint contient JobId, fingerprint de scope, index de frontière et curseur RPC nécessaire. Il ne contient pas de payload ni de secret. Pour LatestAddress, une reprise repart volontairement de la vue latest et s'appuie sur l'idempotence Store ; pour BeforeAddress, elle reprend au dernier curseur contigu ; pour AfterAddress et ExplicitSignatures, elle rejoue le scope borné et ignore uniquement le préfixe validé par le checkpoint.
16. Annulation et courses terminales
Annuler est idempotent et fait passer Running vers Cancelling dès que le producteur observe le token.
| Situation | Décision |
|---|---|
| Attente ou page RPC en cours | Le futur Transport est abandonné par sélection coopérative |
| Hydratation RPC longue | Le futur est abandonné ; aucune persistance n'est fabriquée |
| Candidat pas encore admis | Il ne démarre pas |
| Persistance Store déjà soumise | Elle est attendue et son résultat est compté |
| Dernier travail finit avant observation du cancel | Completed gagne si tout est durable |
| Cancel observé avec travail restant | Cancelled gagne après drainage sûr |
| Erreur fatale et cancel simultanés | L'erreur déjà observée reste la cause ; le snapshot indique l'arrêt des admissions |
Le token ne promet pas l'interruption d'un commit externe. La garantie est l'absence de nouvelle admission et une terminaison avec état connu.
17. États, phases, résultats, logging et sécurité
BackfillSnapshot est complet et borné. Il contient :
- phase
Discovering,Hydrating,PersistingouDraining; - scope sûr réduit à son type, son fingerprint et ses bornes ;
- pages lues, doublons supprimés, candidats sélectionnés, démarrés et terminés ;
- hydratés, manquants, insérés, déjà présents et purgés ;
- observations insérées, déjà présentes et non enregistrées ;
- conflits et échecs classés par code stable ;
- concurrence en vol et checkpoint courant ;
- résultat final
Complete,Partial,CancelledouFailed.
Une transaction Missing produit Completed avec résultat Partial si aucune erreur fatale ne survient. Un conflit, une conversion invalide ou une erreur d'infrastructure après les politiques Transport arrête les admissions et produit Failed.
Transitions autorisées :
CreatedversRunningouCancelledsi l'annulation précède le départ ;RunningversCancelling,CompletedouFailed;CancellingversCancelled,Completedsi la course est déjà entièrement durable, ouFailedsi une erreur déjà observée gagne ;- aucun retour vers un état antérieur et une seule publication terminale immuable.
Logging et sécurité :
- target constant propre à la crate selon les conventions Logging existantes, sans nouveau document
std.jobs.*; - champs sûrs : JobId, fingerprint de scope, phase, codes, bornes et compteurs ;
- pas d'URL, credential, body RPC, payload RAW, SQL, liste de signatures ou texte fournisseur ;
Debugdes types publics borné et redacted, champs privés et enums évolutifs#[non_exhaustive]lorsque pertinent ;- erreurs publiques structurées par
ErrorCode, sans état stringly-typed.
18. Politique de retries
| Opération | Propriétaire du retry | Politique Job |
|---|---|---|
getSignaturesForAddress |
Transport | Aucun retry supplémentaire |
getTransaction |
Transport | Aucun retry supplémentaire |
| Écriture Store | Store ou backend selon son contrat | Aucun retry aveugle |
| Job complet | Hôte futur | Nouvelle exécution explicite avec même JobId ou nouveau JobId |
Les erreurs typées finales du Transport deviennent des codes de résultat Job. Les chaînes de fournisseurs ne sont jamais analysées.
19. Dépendances et firewalls
Graphe prévu :
ksp-job-apivers Core uniquement si nécessaire ;ksp-job-backfill-libversksp-job-api, Core, Logging, Onchain Transport etksp-store-lib;- Tokio, futures, SHA-256, JSON canonique et un décodeur Base58 minimal restent des détails privés du backfill ;
- aucune dépendance vers
ksp-store-api,ksp-store-postgres-lib, App, Config, Wallet, Program API ou Interface ; - aucun retour inverse de Core, Transport, Store ou Logging vers Job ;
- aucun type Tokio, reqwest, deadpool, PostgreSQL ou fournisseur dans l'API publique.
Aucun document Config std.jobs.* n'est introduit. Les réglages de Job sont fournis explicitement par l'hôte ; la composition Config appartient à l'application v0.3.7.
La dépendance Base58 exacte sera ajoutée seulement après audit de version et de features lors de la tranche de conversion.
20. Stratégie de tests et canaries
Tests de ksp-job-api :
- validation et bornes des identifiants ;
- transitions autorisées et états terminaux immuables ;
- annulation cloneable et idempotente ;
- séquence strictement monotone, resynchronisation et conservation terminale ;
- listener lent, plusieurs listeners et listener abandonné sans blocage producteur.
Tests de ksp-job-backfill-lib :
- validation de chaque scope et de toutes les bornes ;
- pagination latest, before et after selon fixtures officielles ;
- ancre after non atteinte, doublons inter-pages et ordre déterministe ;
- signatures explicites dédupliquées à première occurrence ;
- conversion Base58 exacte, RAW v1 déterministe, absent contre
nullet block time négatif ; - provenance de l'endpoint réellement victorieux ;
- Store
Inserted,AlreadyPresent,SkippedPurged, observation déjà présente, conflit et missing ; - relance idempotente avec même JobId et nouvelle observation avec endpoint différent ;
- concurrence bornée, aucune file croissante et front contigu malgré fin désordonnée ;
- annulation pendant découverte, hydratation, attente Transport et persistance ;
- course annulation contre complétion et checkpoint sans saut de trou.
Canaries externes :
- Job API depuis une crate externe, sans construction de champs privés ;
- Backfill depuis une crate externe avec ses types de production opaques ; doubles des ports privés uniquement dans les tests internes ;
- interdiction de dépendance et de type public ;
- smoke opt-in Devnet plus PostgreSQL configuré, sans endpoint payant ni secret versionné.
21. Sizing recalibré — prereleases souples
Chaque tranche technique vise environ 15 à 20 minutes de travail effectif lorsque le sujet s'y prête. Cette durée est une cible de granularité, pas une durée maximale de compilation, diagnostic ou preuve live.
Le forecast reste souple : une tranche peut être scindée, fusionnée ou réordonnée par delta si la réalité technique l'exige, sans fusionner les couloirs de fermeture. Un correctif est inséré sous sa prerelease avec un titre #### pre.NNN-fix.MMM afin de conserver une hiérarchie éditable.
pre.001 — Audit, décisions, plan et validation
Statut : réalisé ; corrigé par pre.001-fix.001.
Budget cible : 15-20 min. L'entrée exigeait la stable v0.3.5 et les deux archives vérifiées. La tranche a produit l'audit KSP, kbot3 et RPC officiel, les décisions d'ownership, le plan, la validation et le bump 0.3.6-pre.1, sans crate ni code Rust. La sortie est la surface de travail acceptée pour Job API et Backfill.
pre.001-fix.001 — Sizing éditable et audit Markdown effectif
Statut : réalisé ; correctif d'outillage et documentaire.
Le sizing tabulaire est remplacé par les présentes sous-sections afin que chaque correctif futur reste sous sa prerelease. Le validateur Markdown reconnaît désormais les séparateurs plausibles contenant des espaces erronés, applique l'alignement source gauche, droit ou centré indiqué par les marqueurs et possède des tests de régression. Les tableaux de pre.001 sont réellement réalignés. Comme le script d'audit est du code d'outillage consommé par le gate, la version Cargo devient 0.3.6-pre.1.fix.1.
pre.002 — Identité, lifecycle et annulation Job API
Statut : planifié.
Budget cible : 15-20 min. Entrée : plan 027 corrigé et gate Markdown fiable. Implémenter uniquement identité, transitions et token d'annulation runtime-neutral. Sortie : unitaires API et firewalls verts, sans notification concrète ni backfill.
pre.003 — Notifications latest-value génériques
Statut : planifié.
Budget cible : 15-20 min. Entrée : transitions Job stables. Implémenter séquences, snapshot source et resynchronisation multi-listeners. Sortie : listener lent, terminal retenu et canary externe API verts.
pre.004 — Provenance Transport observée
Statut : planifié.
Budget cible : 15-20 min. Entrée : besoin de provenance confirmé par le plan. Ajouter le retour observé de getTransaction sans dupliquer le client. Sortie : tests de routage, retry et endpoint réellement victorieux verts.
pre.005 — Fondation Backfill et découverte
Statut : planifié.
Budget cible : 15-20 min. Entrée : Transport observé stable. Créer la crate, les requêtes, scopes, validations, candidats et pagination. Sortie : fixtures latest, before, after et explicite, avec déduplication stable.
pre.006 — Conversion RAW v1 et provenance
Statut : planifié.
Budget cible : 15-20 min. Entrée : candidats déterministes. Implémenter décodage Base58 minimal, payload canonique et provenance. Sortie : golden bytes, hash, absent contre null et block time hostile couverts.
pre.007 — Persistance Store et idempotence
Statut : planifié.
Budget cible : 15-20 min. Entrée : RAW v1 figé. Composer l'écriture atomique Store normale et les outcomes distincts. Sortie : insert, already present, purge, observation, missing, conflit et relance idempotente couverts.
pre.008 — Concurrence, frontier et checkpoint
Statut : planifié.
Budget cible : 15-20 min. Entrée : résultats Store typés. Ajouter admissions bornées, réconciliation hors ordre et reprise. Sortie : frontière contiguë, trous, bornes et checkpoints des quatre scopes prouvés.
pre.009 — Annulation et snapshots concrets
Statut : planifié.
Budget cible : 15-20 min. Entrée : frontière prouvée. Intégrer annulation sur les phases critiques et progression Backfill latest-value. Sortie : courses terminales, drainage Store et listener lent couverts.
pre.010 — Hardening et canaries externes
Statut : planifié.
Budget cible : 15-20 min. Entrée : vertical déterministe complet. Fermer scénarios adversariaux, API externe, dépendances et sécurité ; exécuter la preuve live si justifiée et disponible. Sortie : aucun défaut fonctionnel ou firewall ouvert.
pre.011 — Gate technique final
Statut : planifié.
Budget cible : 15-20 min. Entrée : hardening vert. Rejouer le workspace complet, Clippy, tests et cargo trees, plus le smoke opt-in retenu. Sortie : preuve technique finale consignée sans réconciliation documentaire.
pre.012 — Réconciliation documentaire finale
Statut : planifié.
Budget cible : 10-15 min. Entrée : gate technique final vert. Aligner architecture, index, README, USAGE, plan et validation sur la surface prouvée. Sortie : documentation durable cohérente, sans CHANGELOG, ROADMAP ni prompt suivant.
pre.013 — Préparation de publication minimale
Statut : planifié.
Budget cible : 10-15 min. Entrée : réconciliation documentaire validée. Modifier uniquement la mécanique Cargo/delta, CHANGELOG.md, ROADMAP.md et le prompt v0.3.7. Sortie : archive minimale prête pour le gate de publication.
rel.001 — Stabilisation et tag v0.3.6
Statut : planifié.
Entrée : gate de publication vert. Synchroniser la version stable, livrer le delta rel.001, effectuer les opérations Git séparées et poser le tag stable. Aucun rattrapage fonctionnel ou documentaire n'est admis.
Le smoke live reste conditionnel à un PostgreSQL explicitement configuré. Son absence n'annule pas la preuve déterministe et ne doit pas conduire à inventer un résultat.
22. Critères de fermeture
La v0.3.6 est fermable lorsque :
- les deux crates canoniques existent et respectent les firewalls ;
- Job API reste passive, runtime-neutral et sans dépendance de domaine ;
- l'observation latest-value est non bloquante, multi-listeners et terminalement persistante ;
- les quatre scopes sont bornés, ordonnés, dédupliqués et couverts ;
- le wrapper Transport observé prouve la provenance réelle sans dupliquer sa politique ;
- le format RAW v1 est déterministe et ses canaries couvrent toutes les variantes wire ;
- la persistance passe uniquement par
ksp-store-liben mode normal ; - insertion, déjà présent, purge, observation, missing et conflit restent distinguables ;
- la frontière ne saute aucun trou sous concurrence ou annulation ;
- une relance logique est idempotente ;
- unitaires, canaries externes, audits de règles, tables,
cargo check,cargo clippyetcargo testsont verts dans un environnement Rust disponible ; - les documents d'architecture utilisent
ksp-job-backfill-libet ne promettent aucun Worker ou pipeline partagé prématuré ; - la publication stable suit les lanes documentaires et Git séparées de
VERSION_WORKFLOW.md.