Files
khadhroony-bot3/docs/architecture/STORAGE_ARCHITECTURE.md
2026-08-12 14:31:48 +02:00

9.8 KiB
Raw Blame History

Architecture du stockage

1. Responsabilité de ks-store

ks-store réunit :

  • la façade publique backend-agnostique Store et ses options d'ouverture ;
  • les contrats store-neutral ;
  • les DTO et entités persistés ;
  • la pagination, le replay et les rapports de santé ;
  • les traits de repositories ;
  • les résumés runtime/init sanitisés ;
  • l'implémentation PostgreSQL privée ;
  • les ressources de schéma, maintenance et requêtes appartenant au backend actif.

Depuis 0.5.3-pre.002, les consommateurs ne construisent plus un backend concret. ks-store possède la connexion et le dispatch interne ; PostgresStore, PgPool et SQLx ne traversent plus sa frontière publique.

Depuis 0.5.3-pre.003, PostgreSQL construit directement le nouveau baseline k_sol_* à partir de ressources SQL atomiques ; les migrations historiques 0001 à 0004 ne constituent plus la chaîne active.

2. Frontières

2.1 Contrats store-neutral

Les contrats ne dépendent pas des détails SQL lorsqu'une abstraction stable est suffisante. Ils décrivent les entrées, sorties, identifiants, pages, diagnostics et erreurs nécessaires aux consommateurs. StoreOpenOptions transporte un code backend et un objet d'options opaque ; seul ks-store interprète le moteur sélectionné.

Le résumé runtime expose des modèles logiques et des compteurs d'objets par catégorie sans publier les noms physiques. PostgreSQL expose actuellement des compteurs table et index, tandis qu'un futur backend peut utiliser d'autres catégories sans modifier le desktop.

2.2 Adaptateur PostgreSQL

Le module PostgreSQL possède :

  • la validation de ses options ;
  • la connexion et l'initialisation ;
  • l'orchestrateur transactionnel global du baseline ;
  • les ressources SQL include_str! ;
  • les requêtes typées ;
  • les diagnostics physiques ;
  • les opérations de replay et de sélection de candidats ;
  • le target de tracing canonique ks-store, enrichi des champs backend="postgres", domain="ks-store.pg" et action.

Les détails physiques restent privés. Les erreurs et résumés traversant la façade ne doivent pas divulguer de DSN, password ou option sensible.

2.3 Modèles partagés

Les modèles métier communs restent dans ks-lib lorsqu'ils dépassent la seule persistance. ks-store ne doit pas créer une seconde définition concurrente d'un contrat partagé.

3. Niveaux de persistance

Le stockage distingue quatre niveaux durables :

  • N1 — acquisition et raw canonique ;
  • N2 — Core Solana canonique ;
  • N3 — decode/materialization générique et journaux versionnés ;
  • N4 — projections spécialisées/queryables additives.

N1/N2/N3 constituent la fondation candidate au gel de 0.5.3. Le gel formel n'est déclaré qu'après snapshot et validations de réconciliation ; après clôture, leur évolution normale doit être fortement contrainte. N4 reste volontairement plus évolutif.

Les replays N1 -> N2, N2 -> N3 et N3 -> N4 doivent pouvoir être exécutés indépendamment et de manière idempotente.

4. Baseline N1-N3 de pre.003

Le baseline PostgreSQL comporte 16 tables.

4.1 N1

  • k_sol_raw_transactions ;
  • k_sol_obs_transaction_observations ;
  • k_sol_obs_account_observations.

k_sol_raw_transactions conserve le document canonique source-independent et block_time lorsqu'il est fourni par Solana. Les observations d'acquisition restent séparées de ce document canonique.

k_sol_obs_account_observations réserve un input générique pour les acquisitions d'état de compte : identité du compte, slot/context, bytes exacts, hash et provenance d'acquisition. Cette structure n'est liée à aucun décodeur ou IDL.

4.2 N2 Core

  • k_sol_core_transactions ;
  • k_sol_core_account_keys ;
  • k_sol_core_instructions ;
  • k_sol_core_inner_instructions ;
  • k_sol_core_logs ;
  • k_sol_core_balance_changes ;
  • k_sol_core_return_data ;
  • k_sol_core_account_states.

k_sol_core_transactions porte l'ancre transactionnelle et block_time.

Les instructions top-level et CPI restent physiquement séparées. Les deux portent stack_height lorsque disponible ; les CPI conservent leur parent immédiat reconstructible. Elles doivent converger vers des capacités lifecycle/replay équivalentes sans imposer un stockage physique unique.

k_sol_core_return_data évite de perdre en N2 la returnData déjà présente dans la transaction canonique N1.

k_sol_core_account_states fournit le pendant Core des observations de comptes et conserve les bytes exacts ainsi que leur provenance N1.

4.3 N3 et transverse

  • k_sol_ops_processing_ledger ;
  • k_sol_decode_events ;
  • k_sol_decode_coverage_declarations ;
  • k_sol_decode_coverage_observations ;
  • k_sol_mat_outputs.

k_sol_mat_outputs est le journal générique durable des sorties de matérialisation. Les projections métier N4 ne le remplacent pas.

k_sol_decode_events réserve une provenance de schéma nullable (kind/id/version/hash) pour les mécanismes de décodage pouvant dépendre d'un schéma externe. Les décodeurs compilés actuels la laissent vide.

5. Readiness des futurs décodeurs

Le canari future-decoder ne doit pas introduire Anchor dans le schéma. Il vérifie que les faits Solana génériques suffisants sont conservés :

  • bytes d'instruction et comptes ordonnés ;
  • propriétés signer/writable résolubles ;
  • instructions top-level et CPI ;
  • stack_height et parent CPI ;
  • logs ordonnés ;
  • returnData ;
  • observations/états bruts de comptes ;
  • temporalité et provenance ;
  • identité/version/hash d'un schéma externe lorsqu'un décodeur en utilise un.

La conséquence de pre.003 est l'ajout de trois contrats génériques au-dessus des 13 tables historiques : observation de compte, état Core de compte et return data Core. Le baseline candidat au gel passe donc à 16 tables.

Les métriques transactionnelles comme fee, rewards, compute units et cost units restent disponibles dans N1. Elles ne sont pas requises pour ce canari et ne justifient pas une extension de l'ancre Core en pre.003; une future projection additive pourra les rendre queryables si nécessaire.

6. Ressources PostgreSQL

Les ressources actives sont classées sous :

ks-store/migrations/postgres/
  schema/
    tables/
    constraints/
    indexes/
  maintenance/
    truncate/
    drop/

Principes :

  • une instruction SQL par fichier ;
  • un include_str! privé par ressource ;
  • aucun DDL dupliqué dans une chaîne Rust ;
  • tables avant contraintes, contraintes avant index ;
  • initialisation complète dans une transaction PostgreSQL unique avec advisory lock ;
  • DROP/TRUNCATE séparés de l'auto-init ;
  • refus explicite d'un schéma contenant encore des objets kb_sol_*.

Après la revue repositories/index de pre.004, le baseline contient 240 ressources SQL atomiques et 79 index attendus (63 explicites + 16 index de clés primaires). Ces nombres décrivent l'implémentation PostgreSQL actuelle, pas une API publique gelée.

7. Replay, invalidation et pagination (pre.004)

pre.004 ne modifie pas les 16 tables ; il ferme les chemins de repository au-dessus delles.

7.1 Instructions top-level et CPI

Les deux catégories restent physiquement séparées. La lecture de replay construit une union logique avec un scope explicite et un ordre stable (slot, signature, scope_rank, instruction_path). Le curseur de page reprend cette clé ; aucun OFFSET nappartient au contrat durable.

7.2 Invalidation descendante

Un remplacement N2 Core dune signature invalide dans la même transaction ses descendants N3 decode/coverage/materialization et les ledgers concernés. Un remplacement decode invalide ses sorties de matérialisation pour lidentité exacte decoder name/version/input. Les préfixes de ledger sont comparés littéralement, sans LIKE, afin que _ ne puisse pas agir comme wildcard.

Le lifecycle instructionnel est ensuite recomposé depuis les descendants réellement courants. Une ancienne matérialisation produite par une version antérieure du decoder ne suffit pas à déclarer le nouvel input matérialisé.

7.3 Account observation -> Core account state

Le flux N1 -> N2 réservé en pre.003 devient opérationnel. La sélection est bornée et version-aware ; la présence dun ancien Core state ne masque pas une nouvelle version du normalizer. lamports et rent_epoch conservent tout le domaine u64 via NUMERIC(20,0) et les conversions vers BIGINT échouent explicitement hors domaine signé.

7.4 Bornes et instrumentation

Les lectures interactives publiques sont plafonnées à 500 lignes. Les campagnes de processing Core/decode/account-state utilisent des batches distincts plafonnés à 1 000. Les opérations PostgreSQL réécrites tracent action, durée, lignes et outcome sous ks-store/ks-store.pg, sans SQL brut ni valeur bindée.

8. Propriétés attendues

  • initialisation idempotente ;
  • pagination bornée ;
  • traçabilité des campagnes ;
  • absence de double effet lors des replays ;
  • validation stricte des entrées ;
  • erreurs explicites ;
  • séparation entre acquisition/raw, Core, decode/materialization et projections N4 ;
  • absence de dépendance de N1/N2 à une technologie de décodeur ;
  • conservation des faits nécessaires à un redécodage historique.

Les index non uniques restent des optimisations physiques évolutives. Les noms/colonnes/types/nullabilités/PK/FK/uniques/checks/sémantiques du baseline N1-N3 seront figés séparément lors de la tranche de gel.

9. Données de test

Les fixtures privées, bases locales et preuves temporaires ne font pas partie des livraisons. Les matrices contractuelles partagées restent sous test-fixtures/contract-matrices/ lorsqu'elles sont nécessaires aux tests.