v0.3.8-pre.001

This commit is contained in:
2026-09-03 09:56:41 +02:00
parent 68678a22c6
commit 3df8fc74c1
4 changed files with 866 additions and 2 deletions

View File

@@ -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"

127
deltas/0.3.8/pre.001.md Normal file
View File

@@ -0,0 +1,127 @@
<!-- file: deltas/0.3.8/pre.001.md -->
<!-- version: 1 -->
# 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<T> { 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.

View File

@@ -0,0 +1,624 @@
<!-- file: docs/plans/029-V0_3_8_STORE_DESK_PLAN.md -->
<!-- version: 1 -->
# 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<T> { 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<T>
items: Vec<T>
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<RawTransactionReference>` | cursor | références seulement | table Tx |
| `get_raw_transaction(reference)` | référence Tx | `Option<RawTransaction>` | non | payload jusqu'à 16 MiB | détail Tx |
| `get_raw_transaction_observation(key)` | observation key | `Option<RawTransactionObservation>` | 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<RawAccountStateReference>` | cursor | références seulement | table Account |
| `get_raw_account_state(reference)` | référence Account | `Option<RawAccountState>` | non | data jusqu'à 16 MiB | détail Account |
| `get_raw_account_observation(key)` | observation key | `Option<RawAccountObservation>` | 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<T>` | 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.

View File

@@ -0,0 +1,113 @@
<!-- file: docs/validation/025-V0_3_8_STORE_DESK.md -->
<!-- version: 1 -->
# 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<T>` 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.