# Plan v0.3.7 — Backfill Desk ## 1. But de la version La v0.3.7 crée `ksp-app-backfill-desk`, application Tauri spécialisée qui compose Config, Transport, Store et `ksp-job-backfill-lib` afin de lancer, observer, annuler et reprendre un backfill historique borné. L'application reste une couche de composition et d'interface. Elle ne possède ni découverte RPC, ni retry/rate-limit, ni persistance, ni frontier/checkpoint, ni navigation Store générale. Chaîne cible : ```text Config composite/profile -> Logging -> Transport HTTP -> Store -> AppState Rust -> BackfillRequest -> BackfillJobRuntime -> BackfillJobHandle -> BackfillSnapshotSource -> DTO Tauri sûrs -> UI latest-value ``` ## 2. Base et audits de pre.001 Base autoritaire : archive stable `v0.3.6`, `workspace.package.version = 0.3.6`, avec `deltas/0.3.6/rel.001.md`, `ksp-job-api`, `ksp-job-backfill-lib` et les trois Desks existants. Les deux archives ont été testées intégralement avant utilisation et extraites dans des arbres séparés. kbot3 reste une référence fonctionnelle/UX ; aucun code, DTO, commande Tauri ou algorithme n'en est repris. Sources internes relues : règles racine et `docs/rules/`, architectures Layers/Dependencies/Components/Jobs/Apps, clôture complète de v0.3.6, surfaces Rust Job/Backfill/Config/Transport/Store et gabarits des Desks Config, Wallet et SOL Prices. L'audit externe du 2026-09-02 confirme que le socle Tauri v2, son modèle capabilities/runtime authority et les versions courantes restent compatibles avec les contraintes existantes. Le workspace résout déjà `tauri 2.11.5`, `tauri-build 2.6.3`, `tauri-plugin-tracing 0.3.4` et `ts-rs 12.0.1`; les manifests frontend utilisent `@tauri-apps/api ^2.11`, `@tauri-apps/cli ^2.11`, TypeScript `^7.0` et Vite `^8.2`. Une version plus récente de Vite existe, mais aucun besoin fonctionnel ne justifie une mise à niveau en v0.3.7. ## 3. Surface Backfill réellement disponible `ksp-job-backfill-lib` expose déjà les quatre scopes `LatestAddress`, `BeforeAddress`, `AfterAddress` et `ExplicitSignatures`, les commitments `Confirmed`/`Finalized`, les bornes publiques, `BackfillRequest`, `BackfillCheckpoint`, `BackfillJobRuntime`, `BackfillJobHandle` et `BackfillSnapshotSource`. Le snapshot sûr expose phase, scope kind, boundary, candidats selected/admitted/finished, entities inserted/existing/purged, missing, conflicts, observations inserted/existing, cancelled candidates, holes, maximum in-flight, contiguous completed, présence d'un checkpoint et failure code. L'UI ne fabrique aucun pourcentage global lorsque le dénominateur n'est pas connu. Bornes backend-owned : | Paramètre | Borne publique | |-----------------------|---------------------------------------------:| | page size | 1..=1000 | | max pages | 1..=10000 | | max candidates | 1..=10000 | | hydration concurrency | 1..=64 | | signature Base58 | 64..=88 octets texte, validation Rust exacte | `min_context_slot` est admis pour les scopes adresse et rejeté pour `ExplicitSignatures` par `BackfillRequest`. ## 4. Matrice kbot3 | Capacité historique | Preuve fonctionnelle kbot3 | Équivalent KSP v0.3.6 | Décision | |---------------------------------------------------------|----------------------------------------|---------------------------------------|-----------------------------| | Formulaire de campagne | `demo_backfill.html` + request TS/Rust | `BackfillRequest` explicite et borné | REPRENDRE FONCTIONNELLEMENT | | Signatures explicites | textarea + mode `explicit_signatures` | `BackfillScope::explicit_signatures` | REPRENDRE FONCTIONNELLEMENT | | Adresse + direction | address, anchor, before/after | Latest/Before/After address distincts | REDESSINER POUR KSP | | Commitment | sélecteur confirmed/finalized | `BackfillCommitment` | REPRENDRE FONCTIONNELLEMENT | | Rôle logique | rôle HTTP sélectionnable | `HttpRoleName` + Transport | REDESSINER POUR KSP | | Provider/endpoint affichés | options et summary | Transport possède routage physique | REJETER | | Retry opérateur | `maxRetries` UI | Transport possède retry/pacing | REJETER | | Page size/max pages/limit | inputs bornés | constantes Backfill publiques | REPRENDRE FONCTIONNELLEMENT | | Concurrency | input opérateur | `hydration_concurrency` | REPRENDRE FONCTIONNELLEMENT | | Program/token/pool modes | accordéons dédiés | scopes génériques adresse/signatures | REJETER comme types KSP | | Progression live | événements textuels + log | snapshots latest-value structurés | REDESSINER POUR KSP | | Annulation | bool atomique + commande | `BackfillJobHandle::cancel()` | REDESSINER POUR KSP | | Résumé terminal | payload summary | notification/snapshot terminal | REPRENDRE FONCTIONNELLEMENT | | Compteurs inserted/existing/missing/failed/observations | summary | compteurs `BackfillJobSnapshot` | REDESSINER POUR KSP | | Cursor older-history | `resume_before_signature` | `BackfillCheckpoint` opaque | REDESSINER POUR KSP | | Reprise durable | cursor texte retourné | aucun checkpoint sérialisable public | REPORTER | | Single-run UI | flag `running` | runtime single-run + handle | REPRENDRE FONCTIONNELLEMENT | | Store browsing | demo desktop monolithique | futur Store Desk v0.3.8 | REJETER | ## 5. Screen map Un seul écran principal responsive suffit en V1, en plus du splash commun. ```text main ├─ header : Backfill Desk + statut runtime/config ├─ readiness : profil composite, réseau, rôle(s) compatibles, Store/Transport ready ├─ campaign form │ ├─ scope kind │ ├─ address / anchor / signatures selon scope │ ├─ commitment + rôle logique │ └─ page size / max pages / max candidates / concurrency / min_context_slot ├─ active job │ ├─ lifecycle + phase │ ├─ boundary/frontier │ ├─ compteurs structurés │ ├─ checkpoint présent + contiguous completed │ └─ Start / Cancel selon état ├─ terminal summary │ ├─ outcome/lifecycle │ ├─ failure code sûr │ └─ Resume / New campaign selon checkpoint et scope └─ diagnostics sûrs : codes, jamais secrets/URL/RAW ``` États UI explicites : `booting`, `ready`, `starting`, `running`, `cancelling`, `completed`, `cancelled`, `failed`, `resume-ready`. `cancelling` ne prétend jamais que la persistance déjà soumise est interrompue. ## 6. DTO et command map Les DTOs sont possédés par l'application et dérivés TS-RS uniquement à cette frontière. | Élément | Direction | Contenu | Validation / source de vérité | Sensibilité | |-----------------------------|------------|-----------------------------------------------------------------------------------------------|------------------------------------------|--------------| | `BackfillDeskOptionsDto` | Rust -> UI | réseau, rôles compatibles, commitments, scopes, bornes, readiness | Config + Transport + constantes Backfill | sûre | | `BackfillStartRequestDto` | UI -> Rust | scope inputs, commitment, rôle, bornes, optional min context slot | conversion stricte vers types KSP | métier borné | | `BackfillRunStatusDto` | Rust -> UI | job state, phase, compteurs, boundary, checkpoint_present, contiguous_completed, failure code | `JobNotification` | sûre | | `BackfillCancelResponseDto` | Rust -> UI | accepted + état courant | `BackfillJobHandle` | sûre | | `BackfillResumeResponseDto` | Rust -> UI | accepted/new job status | checkpoint Rust détenu par AppState | sûre | | `SafeAppErrorDto` | Rust -> UI | domain/code + message app maîtrisé | mapping applicatif | sûre | Commandes prévues : ```text backfill_options() -> BackfillDeskOptionsDto backfill_status() -> BackfillRunStatusDto backfill_start(request) -> BackfillRunStatusDto backfill_cancel() -> BackfillCancelResponseDto backfill_resume() -> BackfillResumeResponseDto backfill_reset() -> BackfillRunStatusDto ``` Le monitoring continu ne dépend pas du parsing de logs. Le backend possède un bridge latest-value qui attend `JobSnapshotSource::wait_for_change`, projette le snapshot et émet un événement Tauri borné, par exemple `backfill-status-changed`. `backfill_status` reste le chemin de resynchronisation initiale/explicite. Aucun `BackfillCheckpoint`, `Store`, `HttpTransportPool`, sender/receiver Tokio ni payload RAW n'est sérialisé vers le frontend. ## 7. Config et composition Le composite cible est `config/composite.ksp-app-backfill-desk.json` avec trois profils cohérents : | Profil composite | Logging | Transport | Store | Réseau | |------------------|----------------|----------------------|-----------|----------------| | `devnet` | `supertrace` | `devnet_public` | `devnet` | `devnet` | | `mainnet` | `console_info` | `mainnet_public` | `mainnet` | `mainnet-beta` | | `testnet` | `console_info` | `publicnode_testnet` | `testnet` | `testnet` | Le default V1 est `devnet`, afin de ne pas lancer implicitement une campagne mainnet. Aucun `std.job_backfill.json` n'est créé : les paramètres de campagne restent opérationnels et backend-validés. Au bootstrap, l'application charge le composite, résout Logging/Transport/Store via `ksp-config-lib`, construit `HttpTransportPool` et ouvre `ksp_store_lib::Store`. Elle compare le réseau Store au(x) cluster(s) HTTP activés et refuse le readiness si une composition mélange des réseaux. Les rôles présentés à l'UI sont dérivés des snapshots/settings Transport, dédupliqués, puis validés côté Rust comme capables de sélectionner à la fois `getSignaturesForAddress` et `getTransaction`. Le rôle `default` est actuellement le seul rôle des profils standard, mais il n'est pas codé en dur comme contrat du Desk. Les resources bundle minimales sont le composite Backfill Desk, `std.logging.json`, `std.transport.json`, `std.store.json` et leurs schemas, plus `composite.schema.json`. Les documents Wallet/offchain ne sont pas embarqués sans besoin démontré. ## 8. Dependency map Dépendances Rust normales envisagées : ```text ksp-app-backfill-desk ├─ ksp-core-lib # erreurs, Pubkey/app DTO si requis ├─ ksp-logging-lib # façade logging ├─ ksp-config-lib # composition et packaging Config ├─ ksp-job-api # JobState/JobSnapshotSource consommés directement ├─ ksp-job-backfill-lib # request/runtime/handle/snapshot ├─ ksp-onchain-transport-lib # construction HttpTransportPool + role/method readiness ├─ ksp-store-lib # Store::open et ressource runtime ├─ serde # DTO IPC ├─ tauri ├─ tauri-plugin-tracing ├─ tokio # spawn/synchronisation app si gabarit Tauri l'exige └─ ts-rs # bindings DTO applicatifs ``` `ksp-job-backfill-lib` dépend déjà de Store avec `default-features = false`. Le Desk devra cependant ouvrir le Store concret ; la feature backend de `ksp-store-lib` doit donc être explicitement auditée au scaffold. Le pattern cible est une dépendance sur `ksp-store-lib` uniquement, avec le backend compilé par la feature de façade adéquate, jamais une dépendance directe sur `ksp-store-postgres-lib`. Dépendances interdites : `ksp-store-api` direct, `ksp-store-postgres-lib`, `tokio-postgres`, `reqwest`, `tonic`, `yellowstone-grpc-proto`, SDK provider. ## 9. Single-run lifecycle et races AppState conserve au plus : ressources runtime stables, un slot de run actif, le dernier snapshot terminal et le dernier checkpoint sûr associé à la requête/backend state nécessaires à une reprise en session. Règles : - start atomique : refus si un run est `starting/running/cancelling` ; - le handle est installé avant spawn afin que Cancel ne perde pas la course au démarrage ; - Cancel répété est idempotent au niveau UX, mais le retour expose si la demande a été acceptée ; - un terminal publié gagne sur un Cancel tardif ; - la source latest-value est conservée jusqu'à projection du terminal ; - reset/new campaign n'est autorisé qu'en absence de run actif ; - fermeture de l'application déclenche une demande d'annulation coopérative best-effort puis laisse la destruction du process terminer les ressources ; aucune promesse de drain crash-safe n'est faite ; - aucun registry multi-job générique n'est introduit. ## 10. Reprise et checkpoint V1 conserve le dernier `BackfillCheckpoint` uniquement dans Rust. L'UI voit `checkpoint_present` et `contiguous_completed`, jamais les octets/identité internes du checkpoint. `Resume` reconstruit une requête sémantiquement identique avec un nouveau lifecycle contrôlé et réattache le checkpoint via `BackfillRequest::with_checkpoint`. Le backend doit préserver les éléments participant au scope fingerprint ; toute modification de scope/commitment/bornes sémantiques force une nouvelle campagne et invalide Resume. Aucun JSON, fichier ou table checkpoint n'est inventé. La reprise après crash/redémarrage est reportée à une évolution explicite du contrat Backfill si un besoin durable est démontré. ## 11. Threat model | Menace | Surface | Contrôle v0.3.7 | |------------------------------|------------------|----------------------------------------------------------------------------------------------| | fuite URI Store | Config/backend | jamais projetée en DTO/log frontend | | fuite URL/token provider | Transport/Config | uniquement rôle/cluster/readiness sûrs ; aucune URL | | fuite RAW transaction | snapshots/IPC | snapshot existant ne contient aucun payload ; aucun Store read général | | fuite liste signatures | request/logging | input transmis au command, non journalisé ; DTO retour n'en contient pas | | fuite adresse | instrumentation | ne pas journaliser la valeur ; seulement scope kind/action code | | frontend falsifie bornes | IPC | validation Rust + `BackfillRequest` autoritaire | | rôle incompatible | Config/Transport | inventory + `select_for_method` pour les deux RPC avant Start | | réseau incohérent | Config | rejet bootstrap/readiness avant création de request | | double Start | AppState | admission atomique single-run | | Cancel/terminal race | AppState/runtime | handle installé avant spawn, terminal autoritaire | | checkpoint forgé | frontend | checkpoint jamais traverse IPC | | permissions Tauri excessives | capabilities | `core:default` + `tracing:default`, aucune permission fs/dialog/network frontend sans besoin | | browser storage de secrets | frontend | interdit ; aucun secret ne doit atteindre JS | Tauri capabilities restent le mécanisme de frontière IPC. La capability par défaut doit cibler seulement `splash` et `main` et ne pas ajouter de plugin filesystem/dialog/network sans besoin réel. ## 12. Gate fonctionnel/live Obligatoire pendant la release : tests déterministes Rust/desktop/security/composition, gates workspace et `cargo tauri build` final lancé depuis `crates/ksp-app-backfill-desk`. Un smoke `Config -> Transport -> Store -> Backfill` peut exister comme test ignoré/opt-in uniquement si l'opérateur dispose d'un PostgreSQL de test et d'un endpoint public sûr. Aucun compte payant, secret fournisseur ou ressource non reproductible n'est requis pour clôturer la release. ## 13. Prévision recalibrée ### pre.001 — audit et planification Archives/règles/surfaces, matrice kbot3, screen map, DTO/commands, Config/composition, dépendances, threat model, lifecycle single-run, role/network/resume et sizing. Aucun scaffold lourd. ### pre.002 — scaffold desktop minimal Créer package lib+bin, shell/splash/tracing/capability, frontend minimal, ports Vite/HMR 1436/1437 stricts et tests desktop de structure. ### pre.003 — Config composite et packaging Ajouter composite Backfill Desk, resources minimales, bootstrap Config/Logging et canaries packaging/composition sans encore ouvrir réseau/Store réel. ### pre.004 — Transport readiness Construire `HttpTransportPool`, dériver réseau/role inventory sûr, vérifier support des deux RPC et produire options DTO sans provider/URL. ### pre.005 — Store readiness Ouvrir `ksp-store-lib::Store`, vérifier réseau Store/Transport avant run, lifecycle de fermeture et erreurs sûres. Scinder ici plutôt que mélanger Transport + Store dans une seule tranche large. ### pre.006 — DTO/request mapping DTO TS-RS app-owned, quatre scopes, commitments, min context slot, bornes backend-owned, signatures hostiles et validation de rôle/réseau. ### pre.007 — runtime + Start Single-active-run state, construction `BackfillJobRuntime`, spawn non bloquant, handle installé avant exécution et snapshot initial/terminal. ### pre.008 — monitoring latest-value Bridge de snapshots, status DTO, événements coalescés, compteurs complets, resynchronisation et absence de log parsing. ### pre.009 — Cancel et races terminales Cancel, état cancelling, idempotence UX, concurrence Start/Cancel/terminal, sémantique de drain Store et fermeture app. ### pre.010 — checkpoint/frontier et Resume Projection sûre, conservation Rust-only du checkpoint, reprise in-session et invariants par scope. ### pre.011 — frontend fonctionnel et polish Formulaire complet, états responsive, instrumentation sûre, summary terminal, erreurs, boutons contextuels, aucun secret/browser storage. ### pre.012 — hardening et complétude Tests desktop/security/dependency/composition/release completeness, canaries DTO et scan des dépendances/interdictions. ### pre.013 — gate technique final `cargo fmt`, audits, check/clippy/tests workspace, arbres Cargo utiles, `cargo tauri build`, smoke opt-in si environnement sûr disponible. ### pre.014 — réconciliation documentaire README/USAGE/plan/validation et architecture seulement si la surface finale l'exige. Aucun nouveau runtime. ### pre.015 — préparation publication Prompt 0.3.8, CHANGELOG et ROADMAP uniquement avec le bump prerelease/delta requis. ### rel.001 — publication stable Mécanique de publication `v0.3.7`, sans rattrapage. ## 14. Hors périmètre Store Desk/navigation RAW, Worker API/service daemon, scheduler/registry générique Job, checkpoint durable, retry Job, sélection provider physique, nouveau protocole Transport, migration Store, decoding/materialization, application globale/control desk.