From 3df8fc74c1bb65d7faca6b0840d01b317ae3d6a8 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Thu, 3 Sep 2026 09:56:41 +0200 Subject: [PATCH] v0.3.8-pre.001 --- Cargo.toml | 4 +- deltas/0.3.8/pre.001.md | 127 +++++ docs/plans/029-V0_3_8_STORE_DESK_PLAN.md | 624 +++++++++++++++++++++++ docs/validation/025-V0_3_8_STORE_DESK.md | 113 ++++ 4 files changed, 866 insertions(+), 2 deletions(-) create mode 100644 deltas/0.3.8/pre.001.md create mode 100644 docs/plans/029-V0_3_8_STORE_DESK_PLAN.md create mode 100644 docs/validation/025-V0_3_8_STORE_DESK.md diff --git a/Cargo.toml b/Cargo.toml index 2e87d66..0891090 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 444 +# version: 445 [workspace] resolver = "3" members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.3.7" +version = "0.3.8-pre.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/deltas/0.3.8/pre.001.md b/deltas/0.3.8/pre.001.md new file mode 100644 index 0000000..abba395 --- /dev/null +++ b/deltas/0.3.8/pre.001.md @@ -0,0 +1,127 @@ + + + +# Delta v0.3.8-pre.1 — audit, brainstorming et planification Store Desk + +## Base requise + +```text +v0.3.7 +workspace.package.version = 0.3.7 +``` + +La source de code est exclusivement l'archive stable KSP v0.3.7 fournie. kbot3 a été extrait séparément et utilisé uniquement comme référence fonctionnelle/UX conformément au prompt 027. + +## Résumé + +Cette tranche ouvre v0.3.8 sans scaffold Tauri lourd. Elle vérifie archives/règles, audite Store/API/PostgreSQL, les Desks KSP et DataTables, réaudite les fonctions Store historiques de kbot3, puis fixe capabilities/gaps/screens/tables/pagination/DTO/threat model et sizing. + +Décision centrale issue du brainstorming pagination : + +```text +RawPage cursor/keyset existant = conservé comme primitive canonique machine +nouvelle pagination inspection = offset + limit + totaux + summaries backend-neutral +DataTables serverSide = consommateur de la primitive inspection via Tauri invoke +pagination visible = UNE SEULE, le pager DataTables +``` + +Cette décision évite la double pagination kbot3 sans sacrifier la pagination keyset existante. L'offset/count est confiné à une capability d'inspection réutilisable hors Tauri et à son implémentation backend privée ; aucun DTO DataTables ni SQL n'entre dans l'application ou le contrat RAW canonique. + +## Recalibrage explicite du prompt 027 + +Le prompt supposait initialement une pagination Store cursor distincte d'un paging DataTables local, avec possibilité `paging: false`. `pre.001` avait précisément pour mission de trancher cette question avant planification. Le résultat du brainstorming remplace cette hypothèse UI par : + +```text +séparation des contrats oui +séparation visuelle des pagers non +``` + +Les frontières normatives restent inchangées : Store Desk dépend uniquement de `ksp-store-lib`, aucune dépendance backend/SQL, Config reste owner des targets/secrets, V1 reste read-only et kbot3 reste uniquement fonctionnel. + +## Vérification des archives + +- KSP v0.3.7 : SHA-256 `d57132960e4c280a67e59bea02ce08a61665890bdfb6ef16b7faf1b3c57070ae`, 1 702 entrées, ZIP propre ; +- kbot3 : SHA-256 `ee47643b9f8b582ee8db97b2381ec107e45aef8c009fee44757531514615d318`, 2 501 entrées, ZIP propre ; +- aucune entrée absolue, traversal, séparateur inversé ou lien symbolique ZIP ; +- `workspace.package.version = 0.3.7` et `deltas/0.3.7/rel.001.md` confirmés ; +- Store API/lib/PostgreSQL et Backfill Desk stable confirmés. + +## Audits locaux avant modification + +```text +General Rust rule audit: clean +Rust export completeness audit: 0 candidate(s) +KSP workspace Rust rule audit: clean +Markdown table audit: clean (301 table(s), 687 file(s)) +``` + +`cargo` est absent de l'environnement d'assemblage. `cargo fmt/check/clippy/test` ne sont donc pas déclarés PASS localement. Le journal opérateur fourni rapporte un gate stable v0.3.7 complet et reste une preuve externe de baseline. + +## Audits post-modification + +```text +General Rust rule audit: clean +Rust export completeness audit: 0 candidate(s) +KSP workspace Rust rule audit: clean +Markdown table audit: clean (283 table(s), 153 file(s)) +``` + +Le diff contre la base contient exactement `Cargo.toml`, le plan, la validation et le delta `pre.001`, sans suppression. Les gates Cargo restent non exécutés localement faute de binaire `cargo`. + +## Architecture d'inspection retenue + +Contrats candidats à matérialiser à partir de `pre.003` : + +```text +RawInspectionPageRequest { offset, limit } +RawInspectionPage { items, total_items, filtered_items } +RawTransactionInspectionQuery +RawAccountStateInspectionQuery +RawTransactionSummary +RawAccountStateSummary +RawTransactionInspectionRead +RawAccountStateInspectionRead +``` + +Les traits existants `RawTransactionRead` / `RawAccountStateRead` restent inchangés afin de ne pas casser les implémentations externes et de préserver le chemin keyset. + +DataTables V1 : `serverSide: true`, `ajax` fonction custom vers Tauri, `searching: false`, page length 25/50/100, ordre canonique Store seulement. `recordsTotal` / `recordsFiltered` proviennent des counts exacts Store. Aucun second pager n'est rendu. + +## Décisions complémentaires + +- `GABARIT STORE DESK = KSP` ; aucune source de shell/package/assets/code depuis kbot3 ; +- ports Vite/HMR : 1438/1439 ; +- dépendances KSP V1 : Config + Logging + Store facade ; aucun Store API/PostgreSQL direct ; +- npm : socle KSP + `datatables.net-bs5 ^3.0` ; Select reporté faute de fonction réelle ; +- audit externe du 2026-09-03 : DataTables 3.0.3 / Select 4.0.1 ; ranges KSP conservés ; +- composite prévu : Logging + Store uniquement ; +- navigation initiale : Overview / RAW Transactions / RAW Accounts ; +- observations intégrées aux détails puis listing ajouté après extension Store backend-neutral ; +- rows principales alimentées par summaries Store, sans N+1 ni gros bytes ; +- `u64` projetés comme chaînes décimales IPC ; counts vérifiés JS-safe avant DataTables ; +- V1 strictement read-only. + +## Fichiers ajoutés + +- `docs/plans/029-V0_3_8_STORE_DESK_PLAN.md` ; +- `docs/validation/025-V0_3_8_STORE_DESK.md` ; +- `deltas/0.3.8/pre.001.md`. + +## Fichier modifié + +- `Cargo.toml` : header `444` vers `445`, version workspace `0.3.7` vers `0.3.8-pre.1` conformément à `VER-ID-009`. + +## Non inclus + +- aucune crate `ksp-app-store-desk` encore créée ; +- aucun Rust/TypeScript/HTML/SASS applicatif ; +- aucun composite runtime créé ; +- aucun SQL ou changement backend ; +- aucune capability Store encore ajoutée ; +- aucune reprise de code kbot3 ; +- aucune modification CHANGELOG/ROADMAP ; +- aucune publication stable. + +## Suite prévue + +`pre.002` crée uniquement le scaffold KSP de `ksp-app-store-desk`. `pre.003` introduit ensuite les contrats backend-neutral d'inspection ; `pre.004` et `pre.005` implémentent respectivement les vertical slices PostgreSQL Transaction et Account avant le branchement des tables DataTables métier. diff --git a/docs/plans/029-V0_3_8_STORE_DESK_PLAN.md b/docs/plans/029-V0_3_8_STORE_DESK_PLAN.md new file mode 100644 index 0000000..210b1f7 --- /dev/null +++ b/docs/plans/029-V0_3_8_STORE_DESK_PLAN.md @@ -0,0 +1,624 @@ + + + +# Plan v0.3.8 — Store Desk V1 RAW + +## 1. But de la version + +Créer `ksp-app-store-desk`, Desk Tauri KSP read-only destinée à l'inspection backend-agnostique du Store et à la navigation des données RAW réellement persistées. + +La V1 doit exposer les contrats logiques KSP et jamais le schéma PostgreSQL physique. L'application consomme exclusivement `ksp-store-lib` pour le Store, `ksp-config-lib` pour Config et `ksp-logging-lib` pour le tracing/runtime Logging. + +## 2. Base autoritaire et gate d'ouverture + +Base vérifiée : + +```text +archive : khadhroony-solana-project-v0.3.7.zip +workspace.package.version : 0.3.7 +delta stable : deltas/0.3.7/rel.001.md +prompt : prompts/027-V0_3_8_START_PROMPT.md +``` + +L'archive kbot3 est extraite dans un arbre distinct et ne sert que de référence fonctionnelle/UX. + +### 2.1 Preuve des archives + +| Source | SHA-256 | Entrées | Contrôle ZIP | Rôle | +|--------------------------------------------------------|--------------------------------------------------------------------|--------:|--------------------------------------------------|----------------------------| +| `khadhroony-solana-project-v0.3.7.zip` | `d57132960e4c280a67e59bea02ce08a61665890bdfb6ef16b7faf1b3c57070ae` | 1 702 | propre, aucun traversal/absolu/backslash/symlink | source exclusive de code | +| `khadhroony-bot3_v0.5.3-pre.005-fix010-thelatest1.zip` | `ee47643b9f8b582ee8db97b2381ec107e45aef8c009fee44757531514615d318` | 2 501 | propre, aucun traversal/absolu/backslash/symlink | référence fonctionnelle/UX | + +### 2.2 Baseline locale + +Exécuté avant modification : + +```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 (301 table(s), 687 file(s)) +``` + +`cargo` n'est pas installé dans l'environnement d'assemblage. `cargo fmt`, `cargo check`, Clippy et les tests ciblés ne sont donc pas déclarés PASS localement. Le journal opérateur fourni pour la base stable v0.3.7 rapporte un gate complet incluant ces commandes ; il reste une preuve externe de baseline. + +## 3. Règles et frontières confirmées + +### 3.1 Ownership + +```text +Config/env/secrets -> ksp-config-lib +Store contracts persistés -> ksp-store-api +Store facade consumer -> ksp-store-lib +PostgreSQL physique -> ksp-store-postgres-lib +Logging/tracing runtime -> ksp-logging-lib +Store Desk -> composition + DTO + commands + UX +``` + +### 3.2 Dépendances applicatives prévues + +| Dépendance | Statut Store Desk | Justification | +|--------------------------|-------------------|----------------------------------------------------| +| `ksp-config-lib` | REQUISE | composite, profils, bootstrap Config | +| `ksp-logging-lib` | REQUISE | runtime Logging et tracing KSP | +| `ksp-store-lib` | REQUISE | unique façade Store autorisée | +| `ksp-core-lib` | NON REQUISE V1 | réexports Store suffisants pour les contrats visés | +| `ksp-store-api` | INTERDITE DIRECTE | la Desk ne contourne pas la façade | +| `ksp-store-postgres-lib` | INTERDITE | backend physique privé | +| `tokio-postgres` | INTERDITE | driver physique | +| `deadpool-postgres` | INTERDITE | pool physique | +| Transport RPC/gRPC/WS | INTERDIT V1 | inspection Store uniquement | + +## 4. Gabarit KSP Store Desk + +**GABARIT STORE DESK = KSP.** + +kbot3 n'est jamais une source de package, HTML, SASS, assets, Rust, TypeScript ou versions npm. + +### 4.1 Matrice Desk + +| Élément | Config Desk | Wallet Desk | SOL Prices Desk | Backfill Desk | Choix Store Desk | +|-----------------------------|-------------|-------------|-----------------|---------------|-----------------------------------| +| package Rust lib + bin | oui | oui | oui | oui | identique | +| launcher `main.rs` mince | oui | oui | oui | oui | identique | +| Tauri lib `run()` | oui | oui | oui | oui | identique | +| `tauri.rs` centralisé | oui | oui | oui | oui | identique | +| splash KSP commun | oui | oui | oui | oui | identique, titre Store uniquement | +| shell header/sidebar/footer | oui | oui | oui | oui | identique | +| fonts/assets KSP | oui | oui | oui | oui | identiques | +| tracing frontend | oui | oui | oui | oui | obligatoire | +| Vite strict | 1430/1431 | 1432/1433 | 1434/1435 | 1436/1437 | **1438/1439** | +| DataTables | oui | oui | non | non | oui, inspection `serverSide` RAW | +| Select extension | oui | oui | non | non | non par défaut | + +La sélection DataTables n'est pas justifiée par une action V1 : le détail s'ouvre par une action explicite dans la row. `datatables.net-select-bs5` n'est donc pas requis tant qu'une sélection persistante n'apporte pas une fonction réelle. + +## 5. npm / DataTables map + +Les ranges KSP v0.3.7 observés dans Config/Wallet Desk sont : + +```text +@fltsci/tauri-plugin-tracing ^0.3 +@fortawesome/fontawesome-free ^7.3 +@tauri-apps/api ^2.11 +bootstrap ^5.3 +datatables.net-bs5 ^3.0 +datatables.net-select-bs5 ^4.0 +resize-observer-polyfill ^1.5 +simplebar ^6.3 + +@tauri-apps/cli ^2.11 +@types/bootstrap ^5.2 +@types/node ^26.1 +sass-embedded ^1.102 +typescript ^7.0 +vite ^8.2 +``` + +Audit externe du 2026-09-03 : DataTables stable courant `3.0.3`, Select `4.0.1`. Les ranges KSP `^3.0` / `^4.0` couvrent déjà ces familles ; aucune mise à niveau opportuniste du workspace n'est requise. + +Choix Store Desk : même socle KSP, `datatables.net-bs5 ^3.0`, sans `datatables.net-select-bs5` tant qu'aucun use case de sélection persistante ne le justifie. DataTables est utilisé en `serverSide: true` avec `ajax` sous forme de fonction afin d'appeler les commands Tauri sans requête HTTP directe. + +## 6. Audit DataTables et décision de pagination + +### 6.1 Contrat DataTables réellement requis + +Le mode `serverSide` DataTables échange : + +```text +request : draw + start + length + search/order metadata +response: draw + recordsTotal + recordsFiltered + data +``` + +`start` est un offset absolu zéro-based et `length` la taille de page. DataTables exige les totaux pour construire son pager et son information de dataset. Son option `ajax` accepte une fonction custom : Store Desk peut donc transformer une demande DataTables en `invoke()` Tauri puis appeler le callback DataTables, sans `fetch` réseau. + +### 6.2 Contrat RAW canonique KSP conservé + +KSP v0.3.7 expose : + +```text +RawPageRequest { cursor?: RawPageCursor, limit: RawPageLimit } +RawPage { items, next_cursor? } +``` + +Le backend PostgreSQL implémente une pagination keyset déterministe et opaque. Elle reste la primitive canonique pour workers, backfills, replays et parcours séquentiels volumineux. Aucun contrat existant n'est remplacé, renommé ou affaibli. + +### 6.3 Nouvelle primitive d'inspection backend-neutral + +Le brainstorming conclut qu'une UI d'inspection interactive a un besoin distinct et réutilisable : navigation random-access, taille de page, total exact et summaries sans gros payloads. + +Ajouter une surface Store dédiée, sans nom DataTables : + +```text +RawInspectionPageRequest + offset: u64 + limit: RawPageLimit + +RawInspectionPage + items: Vec + total_items: u64 + filtered_items: u64 + +RawTransactionInspectionQuery +RawAccountStateInspectionQuery +RawTransactionSummary +RawAccountStateSummary +RawTransactionInspectionRead +RawAccountStateInspectionRead +``` + +Sémantique : + +- `total_items` = nombre total de lignes logiques de la famille dans le network du Store, avant filtres optionnels de la query ; +- `filtered_items` = nombre total après filtres Store de la query, avant offset/limit ; +- `offset` = position logique dans l'ordre déterministe de la query ; +- `RawPage*` cursor/keyset reste inchangé et continue d'être préféré pour les parcours machine ; +- aucune structure de Store API ne porte le nom DataTables ou un DTO Tauri. + +Deux traits d'inspection séparés préservent le caractère fine-grained des capabilities et évitent d'ajouter des méthodes aux traits RAW existants, ce qui casserait inutilement les implémentations externes. + +### 6.4 Projection summary obligatoire + +La nouvelle pagination ne doit pas déclencher un N+1 de `get_*` ni transporter 16 MiB par row. Les pages d'inspection retournent directement des summaries logiques. + +`RawTransactionSummary` contient au minimum : référence, slot, block time, format id/version, content hash, taille de payload lorsqu'elle est encore connaissable, retention state. Le payload lui-même reste absent. + +`RawAccountStateSummary` contient au minimum : référence, owner, lamports, executable, rent epoch et data length. Les bytes `data` restent absents. + +Ces projections sont backend-neutral et utiles hors Tauri : CLI d'inspection, diagnostics admin ou API read-only peuvent les consommer. + +### 6.5 Mapping DataTables unique + +Dans Store Desk : + +```text +DataTables start -> RawInspectionPageRequest.offset +DataTables length -> RawInspectionPageRequest.limit +Store total_items -> recordsTotal +Store filtered_items -> recordsFiltered +Store summary items -> data +DataTables draw -> callback draw, jamais une donnée Store +``` + +**Une seule pagination est visible : le pager DataTables.** Aucun contrôle `Premier / Précédent / Suivant` Store supplémentaire n'est rendu. + +La page length DataTables `25 / 50 / 100` est également l'unique taille de page visible et devient directement la limite d'inspection Store. + +### 6.6 Filtres et ordre V1 + +Pour éviter de prétendre supporter une recherche globale que le Store ne possède pas : + +- `searching: false` en V1 ; les filtres Store sont des contrôles explicites hors champ de recherche DataTables ; +- Transactions : slot range optionnelle + direction canonique ; +- Accounts : pubkey exacte optionnelle + slot range + direction canonique ; +- les colonnes arbitraires restent non-orderable tant qu'un ordre backend-neutral n'est pas contracté ; +- le contrôle de direction Store provoque un redraw DataTables depuis `start = 0`. + +Le pager DataTables n'invente donc ni filtre ni tri que le backend ne sait pas appliquer globalement. + +### 6.7 Coût accepté et garde-fous + +Le backend PostgreSQL devra implémenter un chemin d'inspection avec `COUNT` exact et navigation offset. Ce chemin peut être plus coûteux à grande profondeur que keyset ; ce coût est accepté **uniquement pour l'inspection interactive** et ne remplace jamais le chemin cursor. + +Garde-fous : + +- page size UX strictement 25/50/100 ; +- aucun `length = -1` accepté ; +- conversion offset/limit PostgreSQL vérifiée avant I/O ; +- réutiliser le count filtré comme total lorsque la query ne possède aucun filtre optionnel ; +- aucun cache de count dans Store API ; une optimisation/caching éventuelle reste backend/app-owned et mesurée ; +- tests de grand offset et d'overflow ; +- si la profondeur réelle devient pathologique, l'UX pourra être recalibrée sans supprimer la pagination keyset canonique. + +### 6.8 Recalibrage du prompt initial + +Le prompt 027 partait de l'hypothèse « pagination Store opaque distincte du paging local DataTables ». `pre.001` avait explicitement pour mission de brainstormer cette frontière. La décision retenue conserve la séparation **des contrats** mais change la composition UI : + +```text +RAW cursor/keyset = primitive canonique durable, non exposée par le pager Desk +RAW inspection offset/page = primitive dédiée à l'inspection interactive +DataTables pager = unique représentation visuelle de cette primitive d'inspection +``` + +C'est une exception locale et bornée aux passages du prompt qui imposaient `paging: false` ou une double notion de page. Toutes les frontières Store/Config/backend, l'interdiction SQL dans l'app et l'objectif read-only restent inchangés. + +## 7. Audit fonctionnel kbot3 + +| Fonction historique | Source kbot3 observée | Valeur UX | Équivalent KSP V1 | Classification | +|-------------------------------|----------------------------------|-----------------------------|------------------------------------------------|-----------------------------| +| health/diag Store | `demo_store_diag.*` | visibilité opérationnelle | `Store::runtime_snapshot` + `health` | REPRENDRE FONCTIONNELLEMENT | +| refresh manuel | vues diag/raw | resynchronisation explicite | refresh Overview/query | REPRENDRE FONCTIONNELLEMENT | +| tables horizontales | `demo_store_tables.ts` | lisibilité grands tableaux | DataTables KSP + `scrollX` | REPRENDRE FONCTIONNELLEMENT | +| filtre local DataTables | `demo_store_tables.ts` | exploration rapide | filtres Store explicites, pas de search locale | REDESSINER | +| page length DataTables locale | `demo_store_tables.ts` | densité configurable | page size inspection Store 25/50/100 | REDESSINER | +| pagination backend par blocs | `demo_store_block_pagination.ts` | datasets volumineux | pager DataTables -> inspection Store | REDESSINER | +| total rows / total blocks | `demo_store_block_pagination.ts` | repère global | totals exacts inspection | REPRENDRE FONCTIONNELLEMENT | +| stack de cursors frontend | `demo_store_block_pagination.ts` | previous | inutile pour le chemin inspection | REJETER | +| replay candidates | `demo_store_replay_candidates.*` | diagnostics replay | hors Store Desk RAW V1 | REJETER V1 | +| JSON diagnostic détail | tables/raw views | inspection détaillée | détail app-owned borné | REPRENDRE FONCTIONNELLEMENT | +| SQL/repositories physiques | backend historique | implémentation | interdit dans Desk | REJETER | + +kbot3 montre précisément le coût UX de deux paginations successives. KSP reprend l'intention fonctionnelle mais fusionne la navigation visible dans DataTables grâce à la nouvelle capability d'inspection. Aucun code, DTO, SQL ou package kbot3 n'est repris. + +## 8. Capability map Store v0.3.7 + +| Surface / méthode | Entrée | Sortie | Pagination | Taille / sécurité | Utilité UI | +|----------------------------------------|-------------------------------------|-------------------------------------|------------|--------------------------|----------------| +| `Store::runtime_snapshot()` | aucune | `StoreRuntimeSnapshot` | non | safe, sans I/O | Overview | +| `Store::health().await` | aucune | `StoreHealthSnapshot` | non | safe, diagnostics bornés | Overview | +| `list_raw_transactions(query)` | network/range/direction/page | `RawPage` | cursor | références seulement | table Tx | +| `get_raw_transaction(reference)` | référence Tx | `Option` | non | payload jusqu'à 16 MiB | détail Tx | +| `get_raw_transaction_observation(key)` | observation key | `Option` | non | provenance sûre | détail | +| retention read Tx | référence Tx | state/tombstone selon capability | non | métadonnées uniquement | table/detail | +| `list_raw_account_states(query)` | network/pubkey/range/direction/page | `RawPage` | cursor | références seulement | table Account | +| `get_raw_account_state(reference)` | référence Account | `Option` | non | data jusqu'à 16 MiB | détail Account | +| `get_raw_account_observation(key)` | observation key | `Option` | non | provenance sûre | détail | + +## 9. Gap map + +### 9.1 Pagination/summaries d'inspection + +Gap confirmé : v0.3.7 ne possède ni offset random-access, ni count backend-neutral, ni summary page évitant N+1. + +| Besoin UI | Gap v0.3.7 | Contrat candidat | Backend | Coût | +|--------------------------------|----------------------|-----------------------------------------------------|---------------------|-------| +| pager DataTables unique | pas d'offset/count | `RawInspectionPageRequest` + `RawInspectionPage` | PostgreSQL + facade | moyen | +| rows Tx sans payload | références seulement | `RawTransactionSummary` + inspection query/read | PostgreSQL + facade | moyen | +| rows Account sans data | références seulement | `RawAccountStateSummary` + inspection query/read | PostgreSQL + facade | moyen | +| totaux filtrés exacts | aucun count public | `total_items` + `filtered_items` | PostgreSQL | moyen | +| navigation machine performante | déjà présente | conserver `RawPage`/cursor keyset | inchangé | aucun | + +Décision : cette extension est **requise avant les tables métier Store Desk**. Elle est implémentée dans `ksp-store-api`, `ksp-store-lib` et `ksp-store-postgres-lib`, jamais dans l'application. + +### 9.2 Observations + +Gap confirmé : aucune capability backend-neutral de listing des observations transaction/account. + +| Besoin UI | Gap | Contrat candidat | Backend | Coût | +|-----------------------------|-------------------|----------------------------------------------------------|---------------------|-------| +| lister observations Tx | pas de query/list | query d'inspection observation + summary/provenance safe | PostgreSQL + facade | moyen | +| lister observations Account | pas de query/list | query d'inspection observation + summary/provenance safe | PostgreSQL + facade | moyen | +| filtrer par entité | pas de list | filtre référence dans query | PostgreSQL | moyen | + +Si des tables d'observations dédiées utilisent DataTables, elles emploient le même modèle d'inspection offset/count afin de conserver une seule pagination visuelle. Le read par `RawObservationKey` existant reste inchangé pour le détail. + +### 9.3 Diagnostics physiques + +Les counts exposés par `RawInspectionPage` portent sur les **entités logiques de la query**, jamais sur des noms de tables, indexes, schemas ou ressources PostgreSQL. Aucun diagnostic physique ne traverse la façade. + +## 10. Screen map + +Navigation V1 : + +```text +Overview +RAW Transactions +RAW Accounts +``` + +Les observations sont intégrées au **détail de l'entité** dans la V1 initiale. Une table d'observations dédiée n'est ajoutée qu'après extension Store ; si elle existe, elle utilise le même pager DataTables unique via la primitive d'inspection. + +### 10.1 Overview + +Cartes : + +```text +Store target/network logique +backend kind logique +health state +migration state/version/pending +pool safe counters +last stable error code +refresh +``` + +### 10.2 RAW Transactions + +```text +filtres Store : slot min/max, direction, page size +contrôles Store : Premier, Précédent, Suivant, Refresh +filtres Store explicites : dataset complet de la query +table +bouton/interaction Détail +``` + +### 10.3 RAW Accounts + +Même pattern avec filtre pubkey optionnel. + +### 10.4 Detail + +Un panneau/modal Bootstrap non bloquant charge une seule entité et ses métadonnées. Les observations sont chargées séparément. Aucun payload n'est mis dans les rows du tableau. + +## 11. Table / column map + +### 11.1 RawTransaction + +| Colonne | Source Store | IPC | Filtre Store | Order V1 | Copy | Détail seulement | +|-----------------|------------------------------------|----------------|--------------|---------------------|------|------------------| +| signature | `RawTransactionSummary::reference` | texte encodé | non V1 | tie-breaker interne | oui | non | +| slot | `RawTransactionSummary::slot` | texte décimal | range | asc/desc canonique | non | non | +| block time | summary | texte décimal? | non | non | non | non | +| format id | summary | texte borné | non | non | non | non | +| format version | summary | entier JS-safe | non | non | non | non | +| payload size | summary | texte décimal? | non | non | non | non | +| content hash | summary | texte hex | non | non | oui | non | +| retention state | summary | enum/badge | non V1 | non | non | non | +| payload bytes | `get_raw_transaction` | détail borné | non | non | non | **oui** | + +### 11.2 RawAccountState + +| Colonne | Source Store | IPC | Filtre Store | Order V1 | Copy | Détail seulement | +|-------------|-------------------------------------|---------------|--------------|---------------------|------|------------------| +| pubkey | `RawAccountStateSummary::reference` | texte | exact | tie-breaker interne | oui | non | +| slot | summary/reference | texte décimal | range | asc/desc canonique | non | non | +| state hash | summary/reference | texte hex | non | tie-breaker interne | oui | non | +| owner | summary | texte | non | non | oui | non | +| lamports | summary | texte décimal | non | non | non | non | +| executable | summary | bool | non | non | non | non | +| rent epoch | summary | texte décimal | non | non | non | non | +| data length | summary | texte décimal | non | non | non | non | +| data bytes | `get_raw_account_state` | détail borné | non | non | non | **oui** | + +Tous les `u64` Store traversent IPC sous forme de chaînes décimales, sauf valeurs bornées explicitement dans un domaine JS-safe. Les summaries ne transportent jamais payload transaction ou account data. + +## 12. Pagination map finale + +| Action / donnée | Propriétaire | Mapping / règle | +|----------------------------|---------------------|----------------------------------------------------------------------| +| première page | DataTables | `start = 0`, `length = pageLength` | +| page N | DataTables | `start = N * length` -> `RawInspectionPageRequest.offset` | +| page précédente/suivante | DataTables | même mapping offset, aucun cursor UI | +| page length 25/50/100 | DataTables + app | whitelist Rust -> `RawPageLimit` | +| total avant filtres | Store inspection | `total_items` -> `recordsTotal` | +| total après filtres | Store inspection | `filtered_items` -> `recordsFiltered` | +| rows | Store inspection | summaries -> `data` | +| `draw` | DataTables/frontend | recopié comme entier dans le callback, jamais persisté par Store | +| slot/pubkey/direction | Store query | contrôles explicites, redraw depuis page 1 | +| search DataTables | désactivée V1 | aucune recherche locale ou pseudo-globale | +| ordre colonnes arbitraires | désactivé V1 | seule direction canonique Store est supportée | +| cursor/keyset RAW | Store canonical | conservé pour workers/backfills/replay, hors pager visuel Store Desk | + +**Invariant UX : un seul composant de pagination est rendu par table, celui de DataTables.** Aucun pager Store parallèle, aucun « bloc Store » imbriqué et aucune seconde page locale. + +Le frontend utilise `ajax(data, callback)` de DataTables pour appeler une command Tauri ; aucune URL HTTP n'est configurée. Le callback reçoit `draw`, `recordsTotal`, `recordsFiltered` et `data` depuis la projection app-owned. + +## 13. DTO / command map + +Noms candidats stabilisés pour le plan ; les types Store restent réexportés via `ksp-store-lib`, l'application ne dépend pas directement de `ksp-store-api`. + +| Command | Request | Response | Capability Store | +|----------------------------------------|-----------------------------------------------|----------------------------------|------------------------------------| +| `store_runtime_status` | aucune | runtime + health safe DTO | `runtime_snapshot`, `health` | +| `store_query_transactions` | offset/limit/range/direction | summaries + total/filtered total | Tx inspection read | +| `store_get_transaction_detail` | app-owned row identity | detail DTO | get Tx + retention/tombstone | +| `store_query_accounts` | offset/limit/pubkey?/range/direction | summaries + total/filtered total | Account inspection read | +| `store_get_account_detail` | app-owned row identity | detail DTO | get Account | +| `store_query_transaction_observations` | offset/limit + entity filter, après extension | observation summaries + totals | future observation inspection read | +| `store_query_account_observations` | offset/limit + entity filter, après extension | observation summaries + totals | future observation inspection read | + +Request DTO DataTables : seuls `offset`, `limit` et les filtres Store autorisés traversent IPC. `draw`, configuration de colonnes, search strings génériques et metadata DataTables ne deviennent pas un contrat Store. + +Response DTO app-owned : + +```text +rows +records_total_decimal +records_filtered_decimal +``` + +Le frontend convertit les counts vers `number` uniquement après `Number.isSafeInteger`. Une valeur hors domaine JS-safe produit une erreur UX explicite plutôt qu'un arrondi silencieux. Le risque est théorique à l'échelle actuelle mais le contrat reste exact. + +## 14. Composite Config + +Créer : + +```text +config/composite.ksp-app-store-desk.json +``` + +Composition V1 : + +```text +Logging + Store +``` + +Aucun Transport. Le profil sélectionné détermine un seul target/network Store. Changer de target, si exposé ultérieurement, implique fermeture puis réouverture explicite ; la V1 utilise le profil composite au démarrage. + +## 15. Payload/detail policy + +Rows IPC : + +```text +identités +u64 en texte +metadata de payload/data +hashes +états +aucun byte RAW complet +``` + +Detail : + +```text +une entité à la fois +chargement explicite +preview bornée si affichage texte/hex nécessaire +pas de browser persistence +pas de logging du contenu +pas de duplication dans DataTables +``` + +Un export exact de 16 MiB n'est pas requis V1. + +## 16. Threat model + +| Menace / erreur | Mitigation V1 | +|---------------------------------------|-------------------------------------------------------------------------| +| page size 0/pathologique | whitelist UX 25/50/100 + validation Rust | +| `length = -1` DataTables | rejet avant Store | +| offset > capacité backend | conversion checked, erreur statique sans I/O | +| offset très profond | chemin inspection seulement ; keyset canonique conservé pour machines | +| count coûteux | exact seulement pour inspection ; reuse total=filtered sans filtre | +| total > JS safe integer | DTO décimal + conversion checked côté TS | +| range slot inversée | validation DTO + `RawSlotRange::new` | +| pubkey invalide | parsing Rust via type KSP réexporté | +| payload/data jusqu'à 16 MiB | summaries sans bytes, detail-only | +| N+1 massif | supprimé par summaries d'inspection | +| refresh/filtre rapide | DataTables `draw` + génération de filtre ; réponse stale ignorée | +| redraw race | un seul pipeline `ajax` DataTables par table | +| search globale mensongère | `searching: false` V1 | +| ordre colonne non supporté | colonnes non-orderable ; direction Store explicite | +| Store close pendant query | état Rust de fermeture, refus nouvelle admission, close borné | +| URI/backend leak | DTO app-owned safe, aucune erreur Debug backend | +| logging payload/query sensible | instrumentation metadata-only | +| localStorage/sessionStorage/IndexedDB | interdits et testés statiquement | +| SQL/backend physical leak | dependency/security canaries | +| confusion DataTables/RAW cursor | types/traits distincts + tests exacts ; aucun cursor dans le pager Desk | + +## 17. Instrumentation frontend + +Tracer sans secrets/payload/cursor ni contenu de filtres : + +```text +startup / runtime status +refresh +DataTables draw start/end +offset/page length changés +filtre Store changé +direction Store changée +view/tab changé +detail opened/closed +count/query failure par code stable +``` + +`draw`, offset et page length peuvent être journalisés comme metadata numérique sûre. Signature, pubkey, hash, payload, URI, credentials et valeurs de filtre ne sont pas journalisés. + +## 18. Gate live + +Smoke final optionnel, read-only : + +```text +Config -> Store open -> health +-> DataTables first inspection page +-> next/random page via offset +-> filter Store + redraw +-> one transaction detail +-> one account detail +-> close +``` + +Le smoke vérifie aussi la cohérence `recordsTotal/recordsFiltered` sur un dataset contrôlé. Aucune migration destructive, archive, purge ou force-rehydrate n'est déclenchée. + +## 19. Prévision souple recalibrée — prereleases souples + +### pre.001 — audit, brainstorming, architecture et planification + +Archive/règles/prompt, gabarit KSP/npm, audit fonctionnel kbot3, capability/gap/screen/table/pagination/DTO/threat maps. Décision : primitive d'inspection backend-neutral + **un seul pager DataTables visible**. Aucun scaffold lourd. + +### pre.002 — scaffold `ksp-app-store-desk` + +Package lib/bin, ports 1438/1439, shell/splash/assets/fonts/SASS KSP, tracing frontend, capabilities minimales, `datatables.net-bs5` et table skeleton sans données Store. Aucun Store ouvert. + +### pre.003 — contrats Store d'inspection + +Ajouter dans `ksp-store-api` les types page offset/count, queries Tx/Account, summaries sans gros bytes et deux traits read d'inspection. Réexports `ksp-store-lib`, canaris external backend/public API/security. Aucun SQL encore. + +#### pre.003-fix.NNN — correctifs éventuels de contrat + +Lane strictement bornée aux invariants des nouveaux contrats d'inspection. + +### pre.004 — inspection PostgreSQL RawTransaction + +Implémenter summary query, counts exacts, offset/limit checked et trait Tx dans `ksp-store-postgres-lib`, puis dispatch façade Store. Conserver intégralement le listage keyset existant. Tests no-payload/N+1, counts filtres, offset hostile et conformance. + +### pre.005 — inspection PostgreSQL RawAccountState + +Même vertical slice pour Account : pubkey/slot filters, ordre canonique, data length sans data bytes, counts exacts, offset/limit checked, façade et canaris cross-family. + +### pre.006 — composite Config + lifecycle Store + Overview + +Créer `config/composite.ksp-app-store-desk.json`, packaging resources, bootstrap Logging+Store, runtime/health safe et fermeture bornée. + +### pre.007 — RawTransaction DataTables serverSide + détail + +Brancher l'unique pager DataTables via `ajax` function/Tauri invoke, mapping offset/limit/totaux, filtres Store explicites, summary rows, retention badges, détail à la demande et instrumentation. Aucun second pager. + +### pre.008 — RawAccountState DataTables serverSide + détail + +Même intégration pour Account, pubkey/range/direction, summaries JS-safe, détail data borné, responsive/scrollX/copy UX. + +### pre.009 — extension Store observations + +Ajouter les listings/summaries d'observations transaction/account backend-neutral. S'ils sont tabulaires, employer la même primitive d'inspection offset/count ; read-by-key existant reste intact. + +### pre.010 — observations UI + hardening UX + +Intégrer provenance sûre dans les détails/tables retenues, aucune source payload byte, puis hardening des draws, counts, filtres, gros offsets et erreurs. + +### pre.011 — security / dependency / release completeness + +Dependency firewall, Config composition, IPC/security scans, no-browser-storage, exact module/dependency/capability inventories, coexistence cursor + inspection. + +### pre.012 — gate technique final + +`cargo fmt --check`, audits, check/clippy/tests workspace complets selon règles, cargo trees, duplicates, `cargo tauri build`, smoke PostgreSQL read-only opt-in si environnement sûr. + +### pre.013 — réconciliation documentaire finale + +README/USAGE Store Desk, architecture/index, plan/validation. Aucun changement runtime. + +### pre.014 — préparation publication + +Prompt suivant + CHANGELOG + ROADMAP uniquement, avec bump prerelease requis. + +### rel.001 — publication stable + +Publication mécanique `v0.3.8`, aucun rattrapage. + +Le sizing reste crédible pour une session parce que la modification Store est séparée en contrat (`pre.003`), Tx backend (`pre.004`) et Account backend (`pre.005`) avant toute table métier. La pagination cursor existante n'est jamais réécrite. + +## 20. Hors périmètre v0.3.8 + +```text +remplacement/suppression de RawPage cursor/keyset +DataTables-specific DTO dans ksp-store-api +search globale arbitraire DataTables sans contrat Store +tri arbitraire sur toutes les colonnes sans contrat Store +SQL app-owned +backend PostgreSQL direct +actions archive/purge/force-rehydrate +backfill/job control +transport RPC +ingest live +worker lifecycle +STRUCTURAL/DECODED/DOMAIN/materialization +analytics/trading +browser persistence RAW +``` + +L'utilisation de `OFFSET` et `COUNT` est autorisée uniquement dans l'implémentation privée PostgreSQL de la nouvelle capability d'inspection ; elle reste interdite dans l'application et ne remplace pas les queries keyset existantes. + diff --git a/docs/validation/025-V0_3_8_STORE_DESK.md b/docs/validation/025-V0_3_8_STORE_DESK.md new file mode 100644 index 0000000..3f052f8 --- /dev/null +++ b/docs/validation/025-V0_3_8_STORE_DESK.md @@ -0,0 +1,113 @@ + + + +# Validation v0.3.8 — Store Desk V1 RAW + +## 1. Gate `pre.001` + +- [X] archive stable KSP v0.3.7 identifiée comme base exclusive ; +- [X] `workspace.package.version = 0.3.7` avant modification ; +- [X] `deltas/0.3.7/rel.001.md` présent ; +- [X] prompt 027 et règles KSP relus ; +- [X] Store API/lib/PostgreSQL et gabarits Desk audités ; +- [X] archive kbot3 isolée et utilisée uniquement comme référence fonctionnelle/UX ; +- [X] npm/DataTables KSP inventorié ; +- [X] capability/gap/screen/table/pagination/DTO/threat maps produites ; +- [X] décision d'architecture pagination tranchée avant scaffold ; +- [X] aucun code kbot3, SQL app-owned ou scaffold Store Desk livré en `pre.001`. + +## 2. Preuve des archives + +| Source | SHA-256 | Résultat | Usage | +|--------------------------------------------------------|--------------------------------------------------------------------|---------------------------|----------------------------| +| `khadhroony-solana-project-v0.3.7.zip` | `d57132960e4c280a67e59bea02ce08a61665890bdfb6ef16b7faf1b3c57070ae` | 1 702 entrées, ZIP propre | source exclusive de code | +| `khadhroony-bot3_v0.5.3-pre.005-fix010-thelatest1.zip` | `ee47643b9f8b582ee8db97b2381ec107e45aef8c009fee44757531514615d318` | 2 501 entrées, ZIP propre | référence fonctionnelle/UX | + +Aucune entrée absolue, traversal, séparateur inversé ou lien symbolique ZIP n'a été détectée. + +## 3. Baseline locale avant modification + +- [X] `python3 scripts/audit_rust_workspace_rules.py` : propre, zéro candidat d'export ; +- [X] audit Markdown : propre, 301 tables / 687 fichiers ; +- [ ] `cargo fmt --all -- --check` : non exécuté localement, `cargo` absent ; +- [ ] `cargo check --workspace` : non exécuté localement, `cargo` absent ; +- [ ] `cargo clippy --workspace --all-targets` : non exécuté localement, `cargo` absent ; +- [ ] tests ciblés Store/Config : non exécutés localement, `cargo` absent. + +Le journal opérateur fourni pour v0.3.7 rapporte un gate complet. Il reste une preuve externe de baseline et n'est pas présenté comme une exécution locale de `pre.001`. + +## 4. Décision pagination / inspection + +- [X] `RawPageRequest` / `RawPage` cursor-keyset existants sont conservés sans modification ; +- [X] le pager Store Desk ne les expose pas ; +- [X] DataTables `serverSide` exige `start`, `length`, `recordsTotal`, `recordsFiltered` ; +- [X] DataTables accepte `ajax` comme fonction custom, compatible avec un `invoke()` Tauri sans fetch ; +- [X] une primitive Store backend-neutral d'inspection offset/count est justifiée ; +- [X] deux capabilities read fine-grained Tx/Account sont préférées à la modification des traits RAW existants ; +- [X] les pages d'inspection retournent des summaries sans payload/data bytes ; +- [X] `total_items` et `filtered_items` sont exacts dans la sémantique de query ; +- [X] page length UX = 25/50/100 ; `length = -1` interdit ; +- [X] DataTables search arbitraire désactivée en V1 ; +- [X] filtres Store explicites et ordre canonique seulement ; +- [X] **un seul pager est visible : celui de DataTables** ; +- [X] aucun pager « bloc Store » ou paging local imbriqué ne subsiste. + +## 5. Capability gaps et trajectoire + +- [X] list/get RawTransaction cursor existe ; +- [X] list/get RawAccountState cursor existe ; +- [X] read observation par key existe pour Tx et Account ; +- [X] inspection offset/count/summary manque en v0.3.7 ; +- [X] listing observations Tx/Account manque ; +- [X] aucun gap n'est contourné par SQL dans l'app ; +- [X] inspection Tx/Account est planifiée dans Store API/lib/PostgreSQL avant l'UI métier ; +- [X] observation listing reste une extension Store dédiée ultérieure ; +- [X] les counts restent logiques/backend-neutral et n'exposent aucun diagnostic physique PostgreSQL. + +## 6. Gabarit / npm + +- [X] `GABARIT STORE DESK = KSP` ; +- [X] ports réservés 1438/1439 ; +- [X] shell/splash/fonts/assets dérivent uniquement des Desks KSP ; +- [X] `datatables.net-bs5 ^3.0` retenu ; +- [X] Select non retenu par défaut ; +- [X] aucune version/package kbot3 n'est utilisée ; +- [X] audit externe : DataTables 3.0.3 / Select 4.0.1 le 2026-09-03, sans upgrade opportuniste. + +## 7. DTO / sécurité + +- [X] tous les `u64` métier traversent IPC en texte décimal ; +- [X] counts convertis en `number` uniquement après contrôle JS-safe ; +- [X] payload transaction et account data sont detail-only ; +- [X] summaries d'inspection excluent les gros bytes ; +- [X] aucun cursor Store dans le pager DataTables ; +- [X] aucune URI/credential/backend handle/SQL n'est projeté ; +- [X] offset/limit hostiles sont rejetés avant I/O ; +- [X] `draw` DataTables sert uniquement à l'ordonnancement frontend ; +- [X] aucune persistence navigateur RAW ; +- [X] instrumentation exclut payload, URI, secrets et valeurs de filtres. + +## 8. Gates futures + +- [ ] `pre.002` scaffold KSP strict + DataTables skeleton ; +- [ ] `pre.003` contrats Store inspection offset/count/summaries ; +- [ ] `pre.004` PostgreSQL + façade inspection RawTransaction ; +- [ ] `pre.005` PostgreSQL + façade inspection RawAccountState ; +- [ ] `pre.006` composite Logging+Store + Overview/health ; +- [ ] `pre.007` RawTransaction DataTables serverSide + détail ; +- [ ] `pre.008` RawAccountState DataTables serverSide + détail ; +- [ ] `pre.009` observation listing/inspection Store ; +- [ ] `pre.010` observations UI + hardening UX ; +- [ ] `pre.011` security/dependency/release completeness ; +- [ ] `pre.012` gate technique final + Tauri build + smoke read-only opt-in ; +- [ ] `pre.013` réconciliation documentaire ; +- [ ] `pre.014` prompt suivant + CHANGELOG + ROADMAP ; +- [ ] `rel.001` publication stable v0.3.8. + +## 9. Gate post-modification `pre.001` + +- [X] `python3 scripts/audit_rust_workspace_rules.py` : General Rust clean, export completeness 0, KSP workspace Rust clean ; +- [X] `python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.8` : clean, 283 tables / 153 fichiers ; +- [X] diff contre l'archive v0.3.7 : exactement quatre fichiers ajoutés/modifiés, aucune suppression ; +- [X] archive delta testée par `unzip -t` ; +- [ ] gates Cargo : non exécutés dans l'environnement d'assemblage, `cargo` absent.