From 8d4b3b67fbfa26dae22e186f40f2b734ad376a99 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Sat, 29 Aug 2026 16:45:14 +0200 Subject: [PATCH] v0.3.2-pre.001 --- Cargo.toml | 2 +- deltas/0.3.2/pre.001.md | 365 ++++++ .../008-DATA_MATERIALIZATION_AND_STORE.md | 41 +- ...3-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md | 1000 +++++++++++++++++ docs/rules/RULES_DEPENDENCIES.md | 6 +- docs/rules/RULES_KSP.md | 4 +- .../019-V0_3_2_STORE_POSTGRES_FOUNDATION.md | 539 +++++++++ 7 files changed, 1938 insertions(+), 19 deletions(-) create mode 100644 deltas/0.3.2/pre.001.md create mode 100644 docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md create mode 100644 docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md diff --git a/Cargo.toml b/Cargo.toml index 33a8976..1f48f4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ resolver = "3" members = ["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-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.3.1" +version = "0.3.2-pre.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/deltas/0.3.2/pre.001.md b/deltas/0.3.2/pre.001.md new file mode 100644 index 0000000..9af957f --- /dev/null +++ b/deltas/0.3.2/pre.001.md @@ -0,0 +1,365 @@ + + + +# Delta `0.3.2-pre.001` — audit Store/PostgreSQL, runtime foundation et réconciliation du graphe + +## 1. Base requise + +Base directe attendue : + +```text +v0.3.1 +workspace.package.version = 0.3.1 +``` + +Sources obligatoires réellement disponibles : + +```text +khadhroony-solana-project-v0.3.1.zip +khadhroony-bot3_v0.5.3-pre.005-fix010.zip +``` + +La metadata Git n'est pas incluse dans l'archive KSP ; le tag `v0.3.1` ne peut donc pas être interrogé localement. La version Cargo, `deltas/0.3.1/rel.001.md`, le prompt 021, la présence de `ksp-store-api` et l'absence des deux crates runtime concordent avec la base stable requise. + +Commit attendu : + +```text +v0.3.2-pre.001 +``` + +Archive overlay attendue : + +```text +ksp-general-0.3.2-pre.001.zip +``` + +## 2. Objectif + +Ouvrir `0.3.2` uniquement par le gate prévu : + +```text +lecture règles + architecture + 0.3.1 +réaudit kbot3 physique ciblé +réaudit PostgreSQL/tokio-postgres/pool/TLS/migrations +brainstorming runtime/backend +threat model +dependency graph exact +Config std.store candidate +integration test strategy +sizing + prévision souple +réconciliation des règles Store contradictoires découvertes +``` + +Aucune crate runtime, connexion, pool, TLS, migration ou Config Store n'est implémenté dans ce delta. + +## 3. Divergence stable découverte + +La base stable avait déjà adopté le backend séparé dans le plan `0.3.1` et les architectures 003/004/005, mais conservait l'ancien modèle dans : + +```text +KSP-API-006 +DEP-STORE-002 +docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md +``` + +Le prompt 021 demande en plus de relire `DEP-STORE-001..010`, alors que la base ne définissait que `001..008`. + +La réconciliation livrée fixe : + +```text +ksp-store-lib = façade/runtime commune +ksp-store-postgres-lib = backend physique officiel +backend -> ksp-store-api +backend -X-> ksp-store-lib +consumers ordinaires -> ksp-store-lib +``` + +`DEP-STORE-009` et `DEP-STORE-010` sont ajoutées pour rendre la frontière normative explicite. + +## 4. Décisions du gate + +### PostgreSQL/driver + +```text +PostgreSQL minimal supporté : 15 +PostgreSQL de référence : 18.6 +driver : tokio-postgres 0.7.18 +``` + +### Pool + +```text +retenu : deadpool-postgres 0.14.x +rejeté : pool KSP maison sans besoin démontré +rejeté : bb8-postgres pour cette fondation, ownership de connection task moins adapté au close KSP +``` + +### TLS + +```text +tokio-postgres-rustls 0.14.x +rustls 0.23 +aws-lc-rs +native system roots +modes KSP : Disabled / VerifyFull uniquement +``` + +### Migrations + +```text +moteur KSP privé +SQL embarqué +history table ksp_store_schema_migrations +sentinel version 0 +SHA-256 +advisory transaction lock borné +run transactionnel +aucun down automatique +aucune table RAW métier +``` + +`refinery 0.9.2` a été audité mais n'est pas retenu. + +### Config + +```text +std.store V1 possédé par ksp-config-lib +KSP_SECRET_STORE_POSTGRES_URI +settings typés +aucun serde_json::Value backend_options +aucun env/PG*/.pgpass lu par Store/backend +``` + +### Health + +Un health/readiness portable minimal est retenu pour distinguer Store construit, prêt et fermé sans exposer pool/URI/SQL. + +## 5. Graphe cible + +```text +ksp-store-lib +├── ksp-store-api +├── ksp-logging-lib +└── [postgres] ksp-store-postgres-lib + +ksp-store-postgres-lib +├── ksp-store-api +├── ksp-logging-lib +├── tokio +├── tokio-postgres +├── deadpool-postgres +├── tokio-postgres-rustls +├── rustls +└── sha2 +``` + +Feature : + +```text +default = postgres +--no-default-features doit compiler +Postgres connu sans feature -> STORE_BACKEND_NOT_COMPILED avant I/O +``` + +## 6. Héritage kbot3 ciblé + +Surfaces relues : ancien `ks-store`, PostgreSQL, migration resources, health, Config et docs Store. + +Résumé : + +```text +REPRENDRE façade intentionnelle, pool/timeout bornés, advisory lock, health, SQL privé +REDESSINER crates séparées, tokio-postgres, settings typés, TLS, checksum/history, close, errors +REPORTER 16 tables N1-N3, 240 SQL métier, 79 index, repositories/replay/ledgers +REJETER SQLx, monolithe façade/backend, backend_options JSON, env direct, erreurs backend brutes +``` + +Le détail est dans le plan 023. + +## 7. Threat model + +Le plan couvre explicitement : + +```text +credential leak URI/Debug/error/log +PG*/.pgpass bypass Config +connection string hostile +connection storm/unbounded pool +hung connect/migration/shutdown +concurrent migration runners +modified migration/checksum +partial migration +SQL/dynamic identifier injection +feature/config mismatch +connection task leaked/dropped +schema history newer than runtime +server error echo +``` + +## 8. PostgreSQL integration strategy + +Le test `#[ignore]` de `pre.008` lira une URI dédiée depuis stdin, refusera une metadata table préexistante, ne créera aucune table métier et ne détruira ni base ni schema. + +Il prouvera : + +```text +connect >= PostgreSQL 15 +bootstrap initial +idempotence +concurrence +checksum mismatch +rollback d'un échec injecté +health ready +close borné +cleanup metadata créée par le test +``` + +La cible de gate est PostgreSQL 18.6. + +## 9. Sizing recalibré + +La prévision reste : + +```text +pre.001 audit/design/réconciliation normative +pre.002 scaffold + feature graph +pre.003 settings + selection/lifecycle contracts +pre.004 Config std.store +pre.005 connection + deadpool + Rustls +pre.006 migration/bootstrap +pre.007 composition + health/close +pre.008 PostgreSQL integration réelle +pre.009 hardening/completeness/dependency matrix +pre.010 gate technique final +pre.011 réconciliation documentaire finale +pre.012 préparation publication minimale +rel.001 publication stable +``` + +La release reste clôturable sans absorber `RawTransaction` ou `RawAccountState`. + +## 10. Fichiers ajoutés + +```text +docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md +docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md +deltas/0.3.2/pre.001.md +``` + +## 11. Fichiers modifiés + +```text +Cargo.toml +docs/rules/RULES_KSP.md +docs/rules/RULES_DEPENDENCIES.md +docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md +``` + +## 12. Fichiers supprimés + +```text +aucun +``` + +## 13. Version Cargo + +La prerelease non-fix synchronise : + +```text +workspace.package.version = 0.3.2-pre.1 +``` + +Aucune crate runtime n'est encore ajoutée ; le changement versionne le gate `pre.001`. + +## 14. Baseline opérateur `v0.3.1` + +Le journal opérateur fourni à l'ouverture montre notamment : + +```text +cargo fmt --all PASS +audit Rust général / exports / workspace PASS +audit Markdown PASS — 186 tables / 138 fichiers +cargo check --workspace PASS +cargo clippy --workspace --all-targets PASS +tests ciblés dont ksp-store-api PASS +cargo test --workspace PASS +builds Tauri SOL Prices/Wallet/Config Desk PASS +cargo tree -p ksp-store-api --edges normal ksp-store-api -> ksp-core-lib +cargo tree --duplicates exécuté +``` + +Cette preuve de base ne remplace pas le gate après application de `pre.001`. + +## 15. Validations après application + +Dans l’environnement de génération du présent overlay, les contrôles suivants ont été réellement exécutés après 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/0.3.2 + Markdown table audit: clean (186 tables, 124 files) +``` + +`cargo` n’est pas installé dans l’environnement de génération. Les commandes suivantes n’ont donc pas été rejouées ici et ne sont pas déclarées PASS : + +```text +cargo fmt --all +cargo check --workspace +cargo clippy --workspace --all-targets +``` + +Aucun code Rust n’est modifié par `pre.001`; le seul changement Cargo est `workspace.package.version`. Le baseline opérateur `v0.3.1` reste vert, mais ne remplace pas le gate opérateur après application. + +## 16. Validations non requises dans cette tranche + +```text +cargo test -p ksp-store-lib crate encore absente +cargo test -p ksp-store-postgres-lib crate encore absente +PostgreSQL live réservé à pre.008 +pool/TLS connection tests réservés à pre.005+ +migration runtime tests réservés à pre.006+ +``` + +## 17. Questions ouvertes + +Aucune question architecturale ne bloque `pre.002`. + +Les détails d'implémentation volontairement réservés aux tranches dédiées sont : + +```text +noms Rust exacts des settings/errors +mapping deadpool exact des timeouts +construction rustls root store exacte +DDL final de history metadata +forme finale health snapshots +``` + +Ils ne rouvrent pas : + +```text +tokio-postgres +deadpool-postgres +Rustls VerifyFull/Disabled +migrations KSP-owned +backend crate séparée +Config ownership +absence de RAW métier en 0.3.2 +``` + +## 18. Application et validation opérateur + +Après application de l'overlay : + +```bash +cargo fmt --all +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.2 +cargo check --workspace +cargo clippy --workspace --all-targets +``` + +Aucun scaffold Store, SQL, migration runtime ou Config `std.store` ne doit être ajouté à ce delta. diff --git a/docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md b/docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md index fa98f78..de7b452 100644 --- a/docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md +++ b/docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md @@ -1,5 +1,5 @@ - + # Data, Materialization et Store @@ -291,26 +291,39 @@ La première implementation `0.3.1` est volontairement **RAW-only** : elle ne cr Les surfaces CORE/DECODE/SPECIALIZED sont ajoutées quand leurs couches sont réellement ouvertes. -## `ksp-store-lib` +## `ksp-store-lib` et backends physiques -`ksp-store-lib` fournit PostgreSQL comme backend officiel de référence derrière `ksp-store-api`. +`ksp-store-lib` est la façade/runtime Store commune derrière `ksp-store-api`. Il sélectionne uniquement les backends compilés par ses features, convertit ses settings KSP-owned vers le backend retenu, expose le lifecycle commun et masque les objets physiques du moteur. -Il possède : +Il possède notamment : -- migrations ; -- SQL ; -- transactions ; -- mapping backend ; -- pagination ; -- claim/lease lorsque nécessaire ; -- notifications backend si retenues. +- identité et sélection de backend côté façade ; +- settings Store publics KSP-owned indépendants de Config ; +- lifecycle commun `open` / `close` ; +- dispatch vers le backend compilé ; +- mapping des diagnostics/health backend vers une projection portable lorsque cette surface est justifiée ; +- réexport de la surface `ksp-store-api` utile aux consumers. -Il ne possède pas : +Le backend PostgreSQL officiel appartient à `ksp-store-postgres-lib`. Cette crate dépend de `ksp-store-api`, ne dépend jamais de `ksp-store-lib` et possède seule : -- transport réseau ; +- `tokio-postgres` et le pool PostgreSQL ; +- le connecteur TLS PostgreSQL ; +- SQL et statements physiques ; +- transactions PostgreSQL ; +- migrations/bootstrap et metadata de schéma ; +- mapping rows/backend ; +- détails de cursorisation physique ; +- diagnostics PostgreSQL internes. + +`ksp-store-lib` et les crates backend ne possèdent pas : + +- transport réseau d’acquisition ; - decoder Program ; - materializer ; -- orchestration de worker/job. +- orchestration de worker/job ; +- politique de batch, backlog, priorité ou retry de processing. + +La pagination/cursorisation reste un contrat de navigation Store. Une limite demandée par l’appelant peut être validée pour sa forme/sécurité, mais aucun plafond métier global arbitraire ni batch-size de worker n’est introduit par le runtime Store. ## `ksp-materializer-api` et `ksp-materializer-lib` diff --git a/docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md b/docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md new file mode 100644 index 0000000..a327c07 --- /dev/null +++ b/docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md @@ -0,0 +1,1000 @@ + + + +# Plan `0.3.2` — Store/PostgreSQL runtime foundation + +## 1. Objet et base + +Cette release part exclusivement de la stable : + +```text +v0.3.1 +workspace.package.version = 0.3.1 +``` + +Le gate d'ouverture est : + +```text +0.3.2-pre.001 +``` + +Les deux archives requises par le prompt sont disponibles et ont été auditées : + +```text +khadhroony-solana-project-v0.3.1.zip +khadhroony-bot3_v0.5.3-pre.005-fix010.zip +``` + +La metadata Git n'est pas incluse dans l'archive KSP ; le tag `v0.3.1` ne peut donc pas être interrogé localement. Les preuves internes concordantes sont : + +```text +workspace.package.version = 0.3.1 +deltas/0.3.1/rel.001.md présent +prompts/021-V0_3_2_START_PROMPT.md présent +crates/ksp-store-api présent +crates/ksp-store-lib absent +crates/ksp-store-postgres-lib absent +``` + +`ksp-store-api` est conservé comme contrat backend-agnostic publié par `0.3.1`. `0.3.2` ne doit pas le remodeler pour simplifier PostgreSQL. + +## 2. Scope de la release + +`0.3.2` introduit ensemble : + +```text +ksp-store-lib +ksp-store-postgres-lib +Config std.store +connexion/pool/TLS PostgreSQL +moteur privé de migrations/bootstrap +diagnostics/health runtime minimaux +integration test PostgreSQL réel opt-in +``` + +La release reste une fondation runtime/backend. Elle n'implémente aucune persistence métier : + +```text +RawTransaction réservé à 0.3.3 +RawAccountState réservé à 0.3.4 +CORE / DECODE / D3 / D4 hors scope +``` + +Aucune table, index, repository ou capability RAW n'est créé uniquement pour démontrer que PostgreSQL fonctionne. + +## 3. Divergence normative découverte à l'ouverture + +La base stable contient une divergence réelle entre les documents les plus récents et deux règles plus anciennes. + +Les documents déjà cohérents avec la trajectoire `0.3.1` sont : + +```text +docs/plans/022-V0_3_1_STORE_RAW_PLAN.md +docs/architecture/003-COMPONENT_CONTRACTS.md +docs/architecture/004-COMPONENT_INVENTORY.md +docs/architecture/005-DEPENDENCY_GRAPH.md +``` + +Ils imposent : + +```text +ksp-store-lib -> ksp-store-api +ksp-store-lib[postgres] -> ksp-store-postgres-lib +ksp-store-postgres-lib -> ksp-store-api +ksp-store-postgres-lib -X-> ksp-store-lib +``` + +En revanche, la base `v0.3.1` conservait encore : + +```text +KSP-API-006 +DEP-STORE-002 +section ksp-store-lib de docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md +``` + +avec l'ancien modèle où PostgreSQL était physiquement contenu dans `ksp-store-lib`. + +`pre.001` réconcilie cette divergence sans changer le scope : + +```text +KSP-API-006 façade/runtime Store dans ksp-store-lib ; PostgreSQL dans ksp-store-postgres-lib +DEP-STORE-002 façade commune + backends optionnels par feature +DEP-STORE-009 ownership physique PostgreSQL par ksp-store-postgres-lib +DEP-STORE-010 consumers ordinaires -> ksp-store-lib, jamais backend direct +architecture 008 même séparation durable +``` + +Cette réconciliation est un prérequis du scaffold `pre.002` ; elle ne constitue pas une implémentation backend. + +## 4. Graphe Cargo cible + +### 4.1 Graphe KSP + +Le graphe cible de `0.3.2` est : + +```text +ksp-store-lib +├── ksp-store-api +├── ksp-logging-lib +└── [feature postgres] + └── ksp-store-postgres-lib + +ksp-store-postgres-lib +├── ksp-store-api +├── ksp-logging-lib +├── tokio +├── tokio-postgres +├── deadpool-postgres +├── tokio-postgres-rustls +├── rustls +└── sha2 à partir de la tranche migrations +``` + +Interdictions : + +```text +ksp-store-postgres-lib -X-> ksp-store-lib +ksp-store-lib -X-> ksp-config-lib +ksp-store-postgres-lib -X-> ksp-config-lib +ksp-store-* -X-> Transport/Program/Materializer +apps/workers/jobs -X-> ksp-store-postgres-lib +``` + +`ksp-config-lib` pourra dépendre de `ksp-store-lib` pour construire des settings effectifs, comme pour les autres adapters Config -> runtime. + +### 4.2 Features de `ksp-store-lib` + +Contrat retenu : + +```toml +[features] +default = ["postgres"] +postgres = ["dep:ksp-store-postgres-lib"] +``` + +`ksp-store-lib --no-default-features` reste compilable. Le type public identifiant PostgreSQL existe même lorsque la feature n'est pas compilée afin qu'une configuration connue mais indisponible puisse produire une erreur stable et explicite : + +```text +STORE_BACKEND_NOT_COMPILED +``` + +Aucune feature de backend ne modifie `ksp-store-api`. + +### 4.3 Versions externes candidates retenues au gate + +Audit au 29 août 2026 : + +```text +PostgreSQL stable courant 18.6 +tokio-postgres 0.7.18 +deadpool-postgres 0.14.1 +tokio-postgres-rustls 0.14.0 +rustls 0.23 +sha2 0.11.0 +refinery audité mais rejeté 0.9.2 +``` + +Les manifests utiliseront les contraintes compatibles avec `DEP-CARGO-*`, sans pin patch arbitraire. Les versions réellement résolues seront enregistrées par les graphes de la tranche qui les ajoute. + +Licences auditées : + +```text +tokio-postgres MIT OR Apache-2.0 +deadpool-postgres MIT OR Apache-2.0 +tokio-postgres-rustls MIT +sha2 MIT OR Apache-2.0 +refinery MIT +``` + +Sources primaires/techniques consultées : + +```text +https://www.postgresql.org/support/versioning/ +https://www.postgresql.org/docs/current/libpq-ssl.html +https://www.postgresql.org/docs/release/18.6/ +https://docs.rs/tokio-postgres/0.7.18/tokio_postgres/ +https://github.com/rust-postgres/rust-postgres/blob/master/tokio-postgres/Cargo.toml +https://docs.rs/deadpool-postgres/0.14.1/deadpool_postgres/ +https://docs.rs/tokio-postgres-rustls/0.14.0/tokio_postgres_rustls/ +https://docs.rs/sha2/0.11.0/sha2/ +https://docs.rs/refinery/0.9.2/refinery/ +``` + +## 5. PostgreSQL support policy + +### 5.1 Major minimal + +KSP `0.3.2` retient : + +```text +major PostgreSQL minimal supporté : 15 +major testé prioritairement : 18 +patch de référence au gate : 18.6 +``` + +PostgreSQL 14 est encore supporté upstream au moment du gate mais atteint son EOL le 12 novembre 2026. L'ajouter à une nouvelle fondation en août 2026 créerait une dette immédiate sans bénéfice démontré. + +Aucun plafond runtime strict n'est fixé à 18 : un serveur plus récent n'est pas rejeté uniquement à cause de son major. Les garanties de release portent sur le minimum 15 et le major courant réellement testé. + +### 5.2 Driver + +Décision acquise confirmée : + +```text +tokio-postgres +``` + +Raisons : + +```text +driver async natif ciblé +API de transaction explicite +support TLS via MakeTlsConnect +connection future explicite +pas d'ORM ni macro SQL imposée +compatible avec l'ownership backend séparé +``` + +La future implémentation ne doit jamais appeler un chemin qui lit implicitement `PG*`, `.pgpass` ou l'environnement KSP. La configuration `tokio_postgres::Config` est construite uniquement depuis des settings reçus de la façade. + +## 6. Pooling + +### 6.1 Décision + +Le pool externe retenu est : + +```text +deadpool-postgres 0.14.x +``` + +Le choix est fondé sur l'ownership/lifecycle et non sur la popularité. + +L'audit source montre que le manager : + +```text +crée Client + connection future tokio-postgres +spawn la connection future +conserve le JoinHandle dans ClientWrapper +abort le JoinHandle au Drop du wrapper +``` + +Le pool possède aussi un `close()` et des timeouts wait/create/recycle. + +### 6.2 Alternative rejetée + +`bb8-postgres` a été audité comme candidat maintenu, mais son manager spawn la connection future lors de `connect` sans conserver le `JoinHandle` dans l'objet retourné. Cette propriété est moins adaptée au critère KSP : + +```text +aucune connection task orpheline +shutdown borné et observable +ownership explicite du lifecycle +``` + +Construire un pool KSP complet est également rejeté pour `0.3.2` : cela réimplémenterait admission, waiters, recycle et fermeture sans besoin métier démontré. + +### 6.3 Bornes runtime + +Settings KSP candidats, à matérialiser exactement en `pre.003`/`pre.005` : + +```text +max_connections défaut 8 plage 1..64 +connect_timeout_ms défaut 10_000 plage 100..60_000 +pool_wait_timeout_ms défaut 5_000 plage 100..60_000 +pool_create_timeout_ms défaut 10_000 plage 100..60_000 +pool_recycle_timeout_ms défaut 5_000 plage 100..60_000 +shutdown_timeout_ms défaut 5_000 plage 100..30_000 +``` + +Ces bornes sont des garde-fous de ressources/lifecycle, pas des policies de workers/jobs. + +Aucun pool, client, statement cache ou type deadpool/tokio-postgres n'est exposé par `ksp-store-lib`. + +## 7. TLS PostgreSQL + +### 7.1 Connecteur retenu + +Décision : + +```text +tokio-postgres-rustls 0.14.x +rustls 0.23 +crypto provider aws-lc-rs +root store système via native-certs +``` + +Ce choix reste cohérent avec la stack Rustls déjà présente dans le workspace et évite d'ajouter OpenSSL/native-tls comme dépendance fonctionnelle Store. + +### 7.2 Modes publics + +La façade KSP n'expose initialement que : + +```text +Disabled +VerifyFull +``` + +`VerifyFull` signifie : + +```text +TLS obligatoire +chaîne certificat vérifiée contre les roots retenus +nom serveur vérifié par rustls +aucun fallback plaintext +``` + +Les modes `Prefer` et `Require` sans vérification de certificat ne sont pas exposés dans `0.3.2`. Le type `tokio_postgres::config::SslMode` ne suffit donc pas à exprimer la policy publique KSP ; il est un détail backend et sera forcé conformément au mode KSP. + +Custom CA, certificat client/mTLS et pinning sont reportés jusqu'à un besoin concret. Le backend ne lit jamais implicitement `sslrootcert`, `sslcert`, `sslkey` ou des fichiers libpq. + +## 8. Store settings et backend selection + +### 8.1 Ownership + +`StoreSettings` appartient à `ksp-store-lib` et ne dépend pas de Config. + +La forme retenue est typée, sans `serde_json::Value` opaque : + +```text +StoreSettings +└── StoreBackendSettings + └── Postgres(PostgresStoreSettings) +``` + +`PostgresStoreSettings` est un type KSP-owned de la façade, pas un type de `ksp-store-postgres-lib`. Il contient uniquement des primitives/settings KSP et reste disponible sans feature `postgres`. + +Lorsque la feature est active, `ksp-store-lib` convertit en privé ces settings vers un `PostgresBackendSettings` possédé par `ksp-store-postgres-lib`. Ce dernier n'est pas réexporté vers les consumers. + +### 8.2 Surface candidate + +Les groupes de settings sont : + +```text +connection_uri String possédée, Debug redacted, aucun getter de diagnostic +pool bornes de section 6 +tls Disabled ou VerifyFull +bootstrap auto_migrate + migration_timeout_ms + lock_timeout_ms +shutdown_timeout_ms lifecycle commun +``` + +Bornes bootstrap : + +```text +auto_migrate défaut true +migration_timeout_ms défaut 30_000 plage 1_000..300_000 +migration_lock_ms défaut 10_000 plage 100..120_000 +``` + +Il n'existe pas de `Default` qui invente une URI de production. Config et les callers programmatiques doivent construire explicitement le backend settings. + +### 8.3 URI et secrets + +La connexion URI est considérée sensible intégralement, même lorsqu'elle ne contient pas de mot de passe visible. + +Interdictions : + +```text +Debug de l'URI +URI dans ErrorContext +URI dans tracing +URI dans health snapshot +copie d'un message serveur contenant des valeurs arbitraires +``` + +Le backend parse la chaîne avec `tokio-postgres`, mais la policy TLS KSP ne peut pas être contournée par des paramètres URI conflictuels. Les options libpq susceptibles de charger des fichiers ou de modifier la policy TLS ne sont pas implicitement honorées par KSP ; les paramètres effectifs sont construits/normalisés depuis les settings typés. + +## 9. Lifecycle `Store` + +### 9.1 Ouverture + +Surface cible : + +```text +Store::open(settings).await -> Result +``` + +Étapes : + +```text +validate settings +resolve backend kind +reject known backend not compiled before I/O +convert facade settings -> backend settings +construct pool/TLS +prove one bounded backend connection/readiness path +run/verify bootstrap according to auto_migrate +return Store only after readiness success +``` + +Le `Store` n'est pas `Clone` dans la fondation. Aucun pool/client backend ne peut s'échapper de la façade. + +### 9.2 Fermeture + +Surface cible : + +```text +Store::close(self).await -> Result<()> +``` + +La fermeture consomme le Store, ferme le pool, interdit de nouvelles acquisitions et attend la terminaison nécessaire dans la borne `shutdown_timeout_ms`. + +`Drop` reste un fallback best-effort non bloquant ; le contrat de fermeture vérifiable est `close(self).await`. + +Cette forme limite structurellement le risque de close concurrent avec une opération qui emprunte encore le Store. + +### 9.3 Erreurs stables candidates + +Domaine Store commun : + +```text +STORE_SETTINGS_INVALID +STORE_BACKEND_NOT_COMPILED +STORE_BACKEND_OPEN_FAILED +STORE_BACKEND_CLOSED +STORE_SHUTDOWN_TIMEOUT +``` + +Backend PostgreSQL : + +```text +STORE_POSTGRES_CONFIG_INVALID +STORE_POSTGRES_CONNECT_FAILED +STORE_POSTGRES_POOL_TIMEOUT +STORE_POSTGRES_TLS_FAILED +STORE_POSTGRES_MIGRATION_FAILED +STORE_POSTGRES_MIGRATION_MISMATCH +STORE_POSTGRES_SCHEMA_NEWER +STORE_POSTGRES_HEALTH_FAILED +``` + +Le mapping final doit conserver un contexte sûr seulement : backend code, action, état, version de migration non secrète, durée/compteur borné. Aucun texte d'erreur distant arbitraire n'est propagé. + +## 10. Migrations/bootstrap + +### 10.1 Décision + +Le moteur de migrations `0.3.2` est KSP-owned et privé à `ksp-store-postgres-lib`. + +`refinery 0.9.2` a été audité : il fournit migrations embarquées, table d'historique, détection divergent/missing et transaction groupée. Il n'est pas retenu car la fondation KSP a besoin d'un contrat plus petit, d'un nom/table/lock précis, d'un mapping d'erreurs KSP strict et d'un checksum cryptographique explicitement stable. Son checksum courant repose sur un `u64` produit à partir du `DefaultHasher` Rust, ce qui n'est pas le contrat de persistence que KSP souhaite figer. + +### 10.2 Ressources + +Les migrations futures sont : + +```text +SQL statique KSP-owned +embarquées au build avec include_str! +ordonnées par version entière croissante +nom immuable borné +checksum SHA-256 du SQL exact +aucune découverte filesystem runtime +aucun down migration implicite +``` + +Une correction de schéma est une nouvelle migration forward. + +### 10.3 Metadata interne + +`0.3.2` autorise uniquement la relation d'infrastructure fixe : + +```text +ksp_store_schema_migrations +``` + +Elle contient au minimum : + +```text +version BIGINT PRIMARY KEY +name TEXT NOT NULL +checksum TEXT NOT NULL +applied_at TIMESTAMPTZ NOT NULL +``` + +Aucun nom de table/schema n'est configurable par l'utilisateur dans cette fondation. Cela élimine le besoin normal de SQL dynamique pour les identifiants. + +La création/forme de cette table est elle-même protégée par un sentinel de bootstrap version `0` avec checksum connu ; les migrations métier futures commenceront à `1`. + +### 10.4 Algorithme + +Bootstrap : + +```text +acquire dedicated pooled client +begin transaction +acquire advisory transaction lock KSP fixe avec attente bornée +set transaction-local statement timeout depuis valeur bornée +create/verify history metadata +verify bootstrap sentinel +load applied migrations ordered +reject unknown/newer versions +reject missing historical versions +reject name/checksum divergence +apply each pending embedded migration in order +insert corresponding history row +commit once +``` + +L'advisory lock est acquis sans attente infinie : KSP utilise une tentative non bloquante répétée jusqu'à la deadline plutôt qu'un lock bloquant non borné. + +Une erreur de migration fait rollback de la transaction entière du run courant. Les migrations déjà commitées lors d'un run antérieur restent intactes. + +### 10.5 Aucun schéma métier en `0.3.2` + +La liste de migrations de production `0.3.2` ne crée : + +```text +aucune table RawTransaction +aucune table RawAccountState +aucune table CORE/DECODE/SPECIALIZED +aucun index métier +``` + +La seule persistence autorisée est la metadata privée de migration/bootstrap. + +## 11. Health/readiness + +Le health portable est retenu dans `0.3.2`, mais limité à la fondation runtime. + +Justification : + +```text +Store::open doit distinguer construit vs réellement prêt +integration réelle doit prouver connect/bootstrap +ops futures ont besoin d'un diagnostic safe sans pool leak +close doit être observable sans exposer le backend +``` + +Surface candidate dans `ksp-store-lib` : + +```text +StoreHealthState +StoreHealthSnapshot +StoreRuntimeSnapshot +``` + +Projection sûre seulement : + +```text +backend kind +state +pool size/available sous forme de compteurs bornés +schema/migration version courante +pending migration count +last safe error code éventuel +``` + +Interdits : URI, host, username, database name si sensible, SQL, nom physique de relation, server error string, pool/client handles. + +Le backend PostgreSQL peut utiliser `SELECT 1` et une introspection minimale interne, puis mapper son résultat vers la projection portable. + +## 12. Config `std.store` + +### 12.1 Ownership + +Seul `ksp-config-lib` possède : + +```text +config/std.store.json +config/schemas/store.schema.json +config/examples/store.example.json +registry descriptors +placeholder interpolation +.env / process environment +provenance/sensitivity +adapter Config -> StoreSettings +``` + +Store et backend ne dépendent pas de Config et ne lisent aucun environnement. + +### 12.2 Shape candidate + +Le document V1 est profilé comme les autres documents standards : + +```json +{ + "format_version": 1, + "default_profile": "postgres_default", + "profiles": [ + { + "profile_id": "postgres_default", + "backend": "postgres", + "postgres": { + "connection_uri": "${KSP_SECRET_STORE_POSTGRES_URI:-postgresql://localhost/ksp}", + "pool": { + "max_connections": 8, + "connect_timeout_ms": 10000, + "wait_timeout_ms": 5000, + "create_timeout_ms": 10000, + "recycle_timeout_ms": 5000 + }, + "tls": { + "mode": "verify_full" + }, + "bootstrap": { + "auto_migrate": true, + "migration_timeout_ms": 30000, + "migration_lock_timeout_ms": 10000 + }, + "shutdown_timeout_ms": 5000 + } + } + ] +} +``` + +Le fallback localhost est classé `Secret` car il appartient à un placeholder `KSP_SECRET_*`; sa safe projection reste redacted. Il ne provoque aucune connexion automatique. + +`.env.example` ajoutera dans la même tranche : + +```text +# PostgreSQL connection URI used by Config std.store profiles. +# KSP_SECRET_STORE_POSTGRES_URI=postgresql://user:password@localhost/ksp +``` + +La valeur d'exemple commentée n'est jamais un vrai credential. + +### 12.3 Feature mismatch + +Config reconnaît `backend = "postgres"` indépendamment de la feature du consumer. L'adapter peut construire le type public `StoreSettings::Postgres`; c'est `ksp-store-lib` qui retourne `STORE_BACKEND_NOT_COMPILED` si la feature manque. + +Ainsi Config ne doit pas connaître les `cfg(feature = "postgres")` de chaque consumer. + +## 13. Logging et redaction + +Les deux crates runtime auront un `constants.rs` privé avec un target explicite : + +```text +ksp-store-lib target ksp-store-lib +ksp-store-postgres-lib target ksp-store-postgres-lib +``` + +Elles utilisent `ksp-logging-lib`, jamais `tracing` directement comme surface KSP. + +Événements sûrs candidats : + +```text +store_open_start / store_open_ready / store_close +postgres_pool_open / postgres_pool_close +postgres_migration_start / applied / current / failed +postgres_health +``` + +Champs autorisés : action, backend code, durations, counts, migration version/name bornée. Sont interdits URI, SQL, bind values, password, remote error detail et payload arbitraire. + +Le `tracing` transitif éventuel de `deadpool-postgres` reste une dépendance externe interne ; KSP ne le réexporte pas et la politique Logging existante garde les targets externes hors des diagnostics KSP normaux sauf configuration explicite. + +## 14. Audit d'héritage kbot3 ciblé + +L'archive historique a été relue sur : + +```text +ks-store/Cargo.toml +ks-store/src/store.rs +ks-store/src/postgres/** +ks-store/migrations/postgres/** +ks-config/src/store.rs +config/store.config.json +config/schemas/store.schema.json +docs/architecture/STORAGE_ARCHITECTURE.md +docs/guides/POSTGRES_STORAGE.md +``` + +Constats : + +```text +backend PostgreSQL monolithique à l'intérieur de ks-store +SQLx PgPool +StoreOpenOptions avec backend_options serde_json::Value +max_connections / connect_timeout / auto_initialize_schema +initialisation transactionnelle + advisory lock +health SELECT 1 / current_schema / version +schema N1-N3 large et repositories déjà métier +configuration historique capable de résoudre directement environnement KS* +``` + +Classification : + +```text +REPRENDRE + façade backend-agnostic comme intention + pool borné + timeout explicite + auto-init explicite + advisory lock pour bootstrap + health léger + SQL/objets physiques privés + logs structurés sans SQL/binds + +REDESSINER + séparation ksp-store-lib / ksp-store-postgres-lib + tokio-postgres au lieu de SQLx + settings typés au lieu de backend_options JSON + TLS explicite vérifié + migration history version + SHA-256 + lifecycle close explicite + error mapping sans texte SQLx/serveur + Config actuel KSP avec KSP_SECRET_* seulement + +REPORTER + 16 tables N1-N3 historiques + 240 ressources SQL métier + 79 index + repositories RAW/CORE/DECODE + processing ledgers/replay + maintenance DROP/TRUNCATE + +REJETER + SQLx comme driver KSP + backend PostgreSQL physiquement dans la façade + lecture directe de l'environnement par Store/backend + anciens prefixes KS*/KB* + backend options JSON opaques + exposition d'erreurs backend brutes + statut de schéma basé uniquement sur présence d'objets sans historique immuable +``` + +L'archive kbot3 est une source de design historique, jamais une base de copie de code ou de schéma. + +## 15. Threat model `0.3.2` + +### 15.1 Credential/diagnostic leak + +Risque : DSN/password via Debug, errors, tracing, snapshots ou panics. + +Mesures : wrapper/settings Debug redacted, aucun DSN dans ErrorContext, mapping stable des erreurs, aucune remote error string, tests canary avec secret hostile. + +### 15.2 Bypass Config par environnement libpq + +Risque : `PGHOST`, `PGPASSWORD`, `.pgpass`, `sslrootcert` ou autres sources implicites changent le runtime. + +Mesures : Store/backend ne lisent aucun env, configuration driver construite depuis settings explicites, source scanner KSP, integration test stdin sans env. + +### 15.3 Connection string hostile + +Risque : URI surdimensionnée, malformed, options conflictuelles TLS, valeurs loggées. + +Mesures : borne de longueur, parse avant I/O, erreurs génériques, policy TLS typée qui prime, pas d'écho input. + +### 15.4 Connection storm / pool non borné + +Risque : nombre excessif de connexions, waiters ou timeouts infinis. + +Mesures : `max_connections <= 64`, tous les timeouts bornés, deadpool configuré explicitement, aucun retry loop de connexion caché dans Store. + +### 15.5 Hung connect / migration / shutdown + +Risque : futur bloqué indéfiniment. + +Mesures : connect/pool timeouts, migration deadline, advisory try-lock borné, statement timeout local, close timeout. + +### 15.6 Concurrent migration runners + +Risque : DDL/history race. + +Mesures : transaction unique + advisory transaction lock fixe, history relue sous lock, test concurrent réel. + +### 15.7 Historical migration modifiée + +Risque : source rebuildée avec SQL différent sous même version. + +Mesures : nom/version immuables + SHA-256 persisté, mismatch terminal avant migration suivante. + +### 15.8 Migration partielle + +Risque : DDL appliqué sans history ou inversement. + +Mesures : transaction unique pour le run, history insert dans la même transaction, rollback sur erreur, test d'échec injecté privé. + +### 15.9 SQL/dynamic identifier injection + +Risque : nom de schema/table fourni par Config interpolé dans SQL. + +Mesures : aucun nom physique configurable en `0.3.2`; ressources SQL statiques et valeurs paramétrées. + +### 15.10 Feature/config mismatch + +Risque : Config demande PostgreSQL mais binaire sans feature. + +Mesures : type backend connu toujours présent + `STORE_BACKEND_NOT_COMPILED` avant I/O. + +### 15.11 Connection task leaked/dropped + +Risque : future tokio-postgres non pilotée ou tâche orpheline après close. + +Mesures : deadpool-postgres retenu précisément pour ownership du JoinHandle par client wrapper ; aucun client/pool ne fuit de la façade ; close explicite + Drop fallback. + +### 15.12 Schema history newer than runtime + +Risque : ancien binaire lancé contre DB migrée par une version plus récente. + +Mesures : version appliquée inconnue/supérieure => `STORE_POSTGRES_SCHEMA_NEWER`, aucune migration/down automatique. + +### 15.13 Server error echo + +Risque : message PostgreSQL incorpore table/value/credential/SQL snippet. + +Mesures : conversion immédiate vers code KSP + contexte allowlisté ; source error brute non incluse dans Display/Debug public. + +## 16. PostgreSQL integration test réel + +Le test opt-in sera dans `ksp-store-postgres-lib/tests/` et ignoré par défaut. + +Entrée : + +```text +une URI PostgreSQL dédiée lue depuis stdin +aucune variable d'environnement +aucun affichage de l'URI +``` + +Sécurité : + +```text +refuser de démarrer si ksp_store_schema_migrations existe déjà +ne créer aucune table métier +ne DROP ni database ni schema +cleanup best-effort uniquement de la table metadata que le test a prouvé avoir créée +``` + +Scénario minimal : + +```text +connect et major >= 15 +bootstrap initial +second bootstrap idempotent +deux bootstrap concurrents après reset contrôlé +corruption test-only du checksum sentinel -> mismatch explicite +restore/reset contrôlé +migration failure injectée sous cfg(test) -> rollback/history inchangée +health ready +close explicite borné +cleanup metadata +``` + +Le gate de référence visera PostgreSQL 18.6. Le test peut accepter un serveur >= 15, mais le rapport opérateur doit enregistrer le major réellement utilisé sans imprimer d'identité sensible. + +## 17. Validation de dépendances et API + +Canaris à créer au fil des tranches : + +```text +ksp-store-lib --no-default-features compile +postgres est feature default +known-but-not-compiled error observable +ksp-store-postgres-lib ne dépend pas ksp-store-lib +Store/backend ne dépendent pas Config/Transport/Program/Materializer +Store/backend production sources ne lisent pas env +aucun type tokio-postgres/deadpool/rustls dans crate root ksp-store-lib +ksp-store-api inchangé et dépend toujours seulement de ksp-core-lib +aucune des 10 capabilities RAW implémentée par PostgreSQL en 0.3.2 +aucune table RAW créée par migrations +``` + +La façade `ksp-store-lib` réexportera la surface crate-root de `ksp-store-api` nécessaire aux consumers, mais ne réexportera aucun type `ksp-store-postgres-lib`. + +## 18. Sizing et prévision souple recalibrée + +Le scope reste clôturable dans une session si les responsabilités restent fines. La prévision initiale du prompt est conservée avec deux précisions : la réconciliation normative est absorbée par `pre.001`, et le choix migrations KSP-owned évite une tranche supplémentaire. + +### `pre.001` — Audit, design, threat model et réconciliation normative + +Livrer le présent plan, la matrice validation, l'audit externe/kbot3, les décisions pool/TLS/migrations/Config, le graphe exact et la correction des règles Store obsolètes. Aucun code runtime. + +### `pre.002` — Scaffold des deux crates + feature graph + +Créer les crates, manifests, modules minimaux, `postgres` default, `--no-default-features`, constants/logging targets et canaris de dépendances. Ajouter seulement les dépendances nécessaires au scaffold retenu. + +### `pre.003` — Settings + backend selection + lifecycle contracts + +Matérialiser `StoreSettings`, `StoreBackendSettings`, `PostgresStoreSettings`, erreurs stable, façade `Store` sans connexion lourde et réexports API. Tester la feature mismatch. + +### `pre.004` — Config `std.store` + +Document/schema/example/registry/adaptor, `.env.example`, provenance/sensitivity/redaction, packaging resources strictement nécessaires. Aucun env dans Store/backend. + +### `pre.005` — PostgreSQL connection + deadpool + Rustls + +Implémenter parse/normalisation URI, pool borné, connect/open/close, VerifyFull/Disabled, timeouts et erreurs redacted. Aucun SQL métier. + +### `pre.006` — Migration/bootstrap foundation + +Créer history metadata, sentinel, SHA-256, advisory lock borné, transaction, version/checksum/newer/missing handling et rollback. Aucun schéma RAW. + +### `pre.007` — Composition end-to-end + health + +Fermer `StoreSettings -> Store -> PostgresBackend`, health/readiness portable, close et mapping diagnostics. + +### `pre.008` — PostgreSQL integration réelle + +Ajouter/exécuter le smoke opt-in non destructif : initial/idempotent/concurrent/mismatch/failure/close sur serveur réel. + +### `pre.009` — Hardening/completeness/dependency matrix + +Inputs hostiles, redaction, no-env, exact exports/modules, external backend compatibility, `--no-default-features`, graphes/features/duplicates, non-régression API. + +### `pre.010` — Gate technique final + +Workspace/clippy/tests, targeted tests, PostgreSQL live gate, graphes Cargo finaux. Aucun développement fonctionnel nouveau. + +### `pre.011` — Réconciliation documentaire finale + +README/USAGE des deux crates, plan/validation/indexes/architecture réellement impactés. Pas de CHANGELOG/ROADMAP/prompt suivant. + +### `pre.012` — Préparation de publication minimale + +Uniquement la lane autorisée : + +```text +Cargo.toml +CHANGELOG.md +ROADMAP.md +prompts/022-V0_3_3_START_PROMPT.md +deltas/0.3.2/pre.012.md +``` + +### `rel.001` — Publication stable + +Version stable + delta de publication uniquement. + +## 19. Critères de clôture de la release + +`0.3.2` ne ferme que si : + +```text +les deux crates existent +feature postgres default et no-default compile +graphe backend séparé prouvé +tokio-postgres/deadpool/Rustls bornés et privés +Config std.store possédée par ksp-config-lib +aucune lecture env/PG*/.pgpass dans Store/backend +migration history version/checksum/lock/rollback prouvée +health/readiness safe prouvé +PostgreSQL réel vert +close borné vert +aucun RawTransaction/RawAccountState implémenté +aucun SQL métier RAW livré +ksp-store-api non régressé +README/USAGE et validation réconciliés +workspace/clippy/tests/graphes verts +``` + +## 20. Hors scope explicite + +```text +RawTransaction persistence/queries/retention +RawAccountState persistence/queries/retention +batch/backlog/priority worker/job +claim/lease métier +notifications persistées +replay Core/Decode +schema métier kbot3 +SQLx +ORM +custom CA/mTLS sans besoin concret +maintenance destructive publique +Store Desk +``` + +## 21. Questions restantes + +Aucune question architecturale ne bloque `pre.002`. + +Les détails suivants sont réservés à leur tranche sans rouvrir les décisions du gate : + +```text +nom exact des structs/methods settings en pre.003 +codes numériques/strings finaux des ErrorCode en pre.003 +mapping exact deadpool timeouts en pre.005 +construction exacte du rustls RootCertStore en pre.005 +DDL précis de ksp_store_schema_migrations en pre.006 +forme finale des snapshots health en pre.007 +``` + +Toute découverte qui exigerait : + +```text +un type PostgreSQL dans ksp-store-api +une dépendance backend -> ksp-store-lib +une lecture directe d'environnement +une table RAW métier dans 0.3.2 +``` + +est considérée comme contradiction architecturale et doit être réauditée avant poursuite. diff --git a/docs/rules/RULES_DEPENDENCIES.md b/docs/rules/RULES_DEPENDENCIES.md index 2c435c8..4d44e25 100644 --- a/docs/rules/RULES_DEPENDENCIES.md +++ b/docs/rules/RULES_DEPENDENCIES.md @@ -1,5 +1,5 @@ - + # Règles des dépendances KSP @@ -79,13 +79,15 @@ Elles complètent les règles Rust générales et le graphe de `docs/architectur - **DEP-MAT-002** — `ksp-materializer-api` et `ksp-materializer-lib` ne dépendent pas de `ksp-store-api` ou `ksp-store-lib`. - **DEP-MAT-003** — Une matérialisation générique doit pouvoir produire un output compatible avec le journal D3 sans imposer une table PostgreSQL spécialisée par materializer. - **DEP-STORE-001** — `ksp-store-api` ne dépend pas de Program, Materializer ou Transport. -- **DEP-STORE-002** — `ksp-store-lib` dépend de `ksp-store-api` et contient l'implémentation PostgreSQL de référence ; il ne dépend pas des implémentations Program/Materializer/Transport. +- **DEP-STORE-002** — `ksp-store-lib` dépend de `ksp-store-api`, porte la façade/runtime Store commune et peut dépendre optionnellement de crates backend compilées par feature ; il ne dépend pas des implémentations Program/Materializer/Transport. - **DEP-STORE-003** — Les workers/jobs spécialisés sont propriétaires des conversions entre modèles runtime et DTO persistants. - **DEP-STORE-004** — Les niveaux durables sont D1 Raw, D2 Core canonique, D3 journal de matérialisation générique et D4 projections spécialisées. - **DEP-STORE-005** — Les replays D1 -> D2, D2 -> D3 et D3 -> D4 doivent pouvoir être exécutés indépendamment. - **DEP-STORE-006** — Une notification de donnée persistée ne constitue jamais la source de vérité du backlog ; les queries Store et marqueurs durables d'idempotence/version de processor font autorité. - **DEP-STORE-007** — Une notification de donnée est publiée seulement après persistence/commit réussis. - **DEP-STORE-008** — D4 est organisé par faits canoniques quand les invariants le permettent, et non par familles de tables propres aux protocoles. +- **DEP-STORE-009** — `ksp-store-postgres-lib` dépend de `ksp-store-api`, possède seul le driver, le pool, TLS, SQL et les migrations PostgreSQL physiques, et ne dépend jamais de `ksp-store-lib`. +- **DEP-STORE-010** — Les consumers runtime ordinaires — workers, jobs, services et apps — dépendent de `ksp-store-lib` et non directement d’une crate backend ; Config/composition traduit la configuration effective vers les settings publics Store sans créer de dépendance Store -> Config. ## Transport diff --git a/docs/rules/RULES_KSP.md b/docs/rules/RULES_KSP.md index 7592b4c..910f6e5 100644 --- a/docs/rules/RULES_KSP.md +++ b/docs/rules/RULES_KSP.md @@ -1,5 +1,5 @@ - + # Règles spécifiques à KSP @@ -23,7 +23,7 @@ - **KSP-API-003** — KSP ne crée pas de `ksp-api-lib` monolithique regroupant les contrats de domaines indépendants. - **KSP-API-004** — Un contrat public extensible doit pouvoir être implémenté depuis une crate séparée du workspace principal lorsque cela est techniquement pertinent. - **KSP-API-005** — Les signatures des contrats publics utilisent en priorité des types publics KSP et les primitives externes explicitement admises ; elles ne doivent pas imposer des détails internes instables. -- **KSP-API-006** — `ksp-store-lib` contient PostgreSQL comme implémentation officielle de référence derrière `ksp-store-api`. +- **KSP-API-006** — `ksp-store-lib` est la façade/runtime Store commune derrière `ksp-store-api` et sélectionne uniquement des backends compilés via ses features ; l’implémentation PostgreSQL officielle appartient à `ksp-store-postgres-lib`, qui dépend de `ksp-store-api` et ne dépend jamais de `ksp-store-lib`. - **KSP-API-007** — Une crate `*-api` n'est créée que lorsqu'un vrai besoin d'extension, backend ou lifecycle le justifie ; la symétrie de nommage n'est jamais une justification suffisante. ## Configuration et environnement diff --git a/docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md b/docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md new file mode 100644 index 0000000..5e04a54 --- /dev/null +++ b/docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md @@ -0,0 +1,539 @@ + + + +# Validation `0.3.2` — Store/PostgreSQL runtime foundation + +## 1. Objet + +Cette matrice est ouverte par `0.3.2-pre.001`. Elle fixe les critères de preuve de la fondation Store/PostgreSQL sans préjuger des résultats non encore exécutés. + +Statuts : + +```text +TODO preuve requise non encore exécutée +PASS preuve réellement exécutée et verte +FAIL preuve exécutée et en échec +N/A non applicable avec justification +``` + +Aucun `TODO` n'est présenté comme validé. + +## 2. Base et audit `pre.001` + +### V32-BASE-001 — Base stable + +Critère : + +```text +workspace.package.version = 0.3.1 sur l'archive source +deltas/0.3.1/rel.001.md présent +prompt 021 présent +ksp-store-api présent +ksp-store-lib absent +ksp-store-postgres-lib absent +``` + +Statut : `PASS` au gate documentaire `pre.001`. + +Note : metadata Git absente de l'archive ; le tag `v0.3.1` n'est pas interrogé localement. + +### V32-AUDIT-001 — Sources internes + +Critère : règles, architecture, plan/validation `0.3.1`, source/tests `ksp-store-api`, CHANGELOG et ROADMAP relus avant design. + +Statut : `PASS` au gate documentaire `pre.001`. + +### V32-AUDIT-002 — Archive kbot3 + +Critère : ancien Store/config/PostgreSQL/migrations/health/pool/erreurs relus et classés reprendre/redessiner/reporter/rejeter. + +Statut : `PASS` au gate documentaire `pre.001`. + +### V32-AUDIT-003 — Audit externe actuel + +Critère : PostgreSQL, tokio-postgres, pool, TLS et helper migrations réaudités avec sources actuelles. + +Statut : `PASS` au gate documentaire `pre.001`. + +Référence du gate : + +```text +PostgreSQL 18.6 +tokio-postgres 0.7.18 +deadpool-postgres 0.14.1 +tokio-postgres-rustls 0.14.0 +sha2 0.11.0 +refinery 0.9.2 audité/rejeté +``` + +## 3. Frontières Cargo + +### V32-DEP-001 — Façade -> API + +```text +ksp-store-lib -> ksp-store-api +``` + +Statut : `TODO pre.002`. + +### V32-DEP-002 — Backend -> API + +```text +ksp-store-postgres-lib -> ksp-store-api +``` + +Statut : `TODO pre.002`. + +### V32-DEP-003 — Pas de cycle backend + +```text +ksp-store-postgres-lib -X-> ksp-store-lib +``` + +Preuves : manifest scanner + cargo tree. + +Statut : `TODO pre.002/pre.009`. + +### V32-DEP-004 — Feature PostgreSQL + +Critères : + +```text +postgres est default feature de ksp-store-lib +ksp-store-postgres-lib est optional dependency +cargo check -p ksp-store-lib --no-default-features passe +``` + +Statut : `TODO pre.002`. + +### V32-DEP-005 — Firewall domaines + +Interdictions : + +```text +Store/backend -> Config +Store/backend -> Transport +Store/backend -> Program +Store/backend -> Materializer +consumer ordinaire -> ksp-store-postgres-lib +``` + +Statut : `TODO pre.009`. + +### V32-DEP-006 — `ksp-store-api` non régressé + +Critères : + +```text +dépendance runtime exacte ksp-core-lib seulement +exports/capabilities existants conservés +aucun type backend ajouté pour PostgreSQL +``` + +Statut : `TODO gate final`, baseline `v0.3.1` déjà verte. + +## 4. Public API et settings + +### V32-API-001 — Settings Config-independent + +Critère : `StoreSettings` est constructible sans `ksp-config-lib`, sans env et sans serde requis par la façade. + +Statut : `TODO pre.003`. + +### V32-API-002 — Backend connu non compilé + +Critère : `Postgres` reste un backend connu sans feature et `Store::open` échoue avant I/O avec un code stable. + +Statut : `TODO pre.003`. + +### V32-API-003 — Aucun type backend physique public + +Interdits dans crate-root `ksp-store-lib` : + +```text +tokio_postgres::* +deadpool_postgres::* +rustls::* +PostgresBackend / Pool / Client / Row / Statement +``` + +Statut : `TODO pre.009`. + +### V32-API-004 — Réexports Store API + +Critère : un consumer de `ksp-store-lib` accède aux contrats Store API utiles sans dépendre directement de la crate backend. + +Statut : `TODO pre.003`. + +### V32-API-005 — Lifecycle + +Critères : + +```text +Store::open async +Store::close(self) async +pas de pool/client échappé +close borné +Drop best-effort seulement +``` + +Statut : `TODO pre.003/pre.007`. + +## 5. Config ownership + +### V32-CONFIG-001 — Document/schema/example + +Critères : + +```text +std.store enregistré +schema V1 valide +example valide +profiles typés +backend postgres explicite +``` + +Statut : `TODO pre.004`. + +### V32-CONFIG-002 — Secrets/provenance + +Critères : + +```text +KSP_SECRET_STORE_POSTGRES_URI classé Secret +safe projection redacted +provenance sans valeur +dotenv inventory à jour +``` + +Statut : `TODO pre.004`. + +### V32-CONFIG-003 — No-env Store/backend + +Critère : production sources `ksp-store-lib` et `ksp-store-postgres-lib` ne lisent aucun : + +```text +std::env +dotenv +KSP_* +KSPB_* +PG* +.pgpass +``` + +Statut : `TODO pre.004/pre.009`. + +### V32-CONFIG-004 — Adapter Config -> Store + +Critère : `ksp-config-lib` seul transforme un profil résolu en `StoreSettings` et ne transmet aucun secret dans diagnostics. + +Statut : `TODO pre.004`. + +## 6. Pool et lifecycle PostgreSQL + +### V32-POOL-001 — Pool borné + +Critères : + +```text +max_connections 1..64 +wait/create/recycle timeouts bornés +aucune taille zéro +aucune valeur pathologique +``` + +Statut : `TODO pre.005`. + +### V32-POOL-002 — Connection task ownership + +Critère : chaque connection future tokio-postgres est pilotée par le manager retenu et son task handle reste possédé jusqu'au drop/close. + +Statut : `TODO pre.005/pre.009`. + +### V32-POOL-003 — Open failure safe + +Critère : DNS/connect/auth/server errors ne copient ni URI ni texte remote arbitraire dans Display/Debug public. + +Statut : `TODO pre.005`. + +### V32-POOL-004 — Close + +Critères : + +```text +pool fermé +nouvelles acquisitions refusées +shutdown respecte timeout +aucune tâche volontairement laissée orpheline +``` + +Statut : `TODO pre.007/pre.008`. + +## 7. TLS + +### V32-TLS-001 — Modes exacts + +Surface initiale : + +```text +Disabled +VerifyFull +``` + +Statut : `TODO pre.005`. + +### V32-TLS-002 — VerifyFull + +Critères : + +```text +TLS requis +root store système +authenticité du certificat vérifiée +nom serveur vérifié +aucun fallback plaintext +``` + +Statut : `TODO pre.005`. + +### V32-TLS-003 — Pas de fichier TLS implicite + +Critère : backend ne lit pas `sslrootcert`, `sslcert`, `sslkey`, `.postgresql/*` ou autre fichier implicite hors settings KSP. + +Statut : `TODO pre.009`. + +## 8. Migration/bootstrap + +### V32-MIG-001 — Metadata privée uniquement + +Critère : `0.3.2` crée au plus la relation d'infrastructure : + +```text +ksp_store_schema_migrations +``` + +et aucune table métier RAW/CORE/DECODE/SPECIALIZED. + +Statut : `TODO pre.006`. + +### V32-MIG-002 — Version/checksum + +Critères : + +```text +version entière monotone +nom immuable +SHA-256 du SQL exact +sentinel bootstrap version 0 +mismatch historique terminal +``` + +Statut : `TODO pre.006`. + +### V32-MIG-003 — Concurrence + +Critère : deux runners concurrents sont sérialisés par advisory transaction lock avec attente bornée. + +Statut : `TODO pre.006/pre.008`. + +### V32-MIG-004 — Atomicité/recovery + +Critère : échec d'une migration du run courant rollback DDL + history de ce run ; un rerun depuis état précédent reste sûr. + +Statut : `TODO pre.006/pre.008`. + +### V32-MIG-005 — Newer runtime guard + +Critère : migration appliquée inconnue/supérieure à la liste embarquée produit `STORE_POSTGRES_SCHEMA_NEWER`, sans down migration. + +Statut : `TODO pre.006`. + +### V32-MIG-006 — SQL injection + +Critères : + +```text +SQL de migration statique embarqué +values paramétrées +aucun identifier physique user-configurable en 0.3.2 +``` + +Statut : `TODO pre.006/pre.009`. + +### V32-MIG-007 — No business capability + +Critères : + +```text +0 impl PostgreSQL de capability RawTransaction +0 impl PostgreSQL de capability RawAccountState +0 repository RAW métier +``` + +Statut : `TODO pre.009/gate final`. + +## 9. Health/readiness + +### V32-HEALTH-001 — Projection portable + +Critère : façade expose uniquement état/backend/counts/migration safe, jamais URI/SQL/pool/client. + +Statut : `TODO pre.007`. + +### V32-HEALTH-002 — Readiness réelle + +Critère : `Store::open` ne retourne Ready qu'après connect + bootstrap/verify selon settings. + +Statut : `TODO pre.007/pre.008`. + +### V32-HEALTH-003 — Error redaction + +Critère : un health failure n'expose pas server error string, query text ou credential. + +Statut : `TODO pre.007/pre.009`. + +## 10. PostgreSQL integration réelle + +### V32-LIVE-001 — Input opérateur explicite + +Critères : + +```text +#[ignore] +URI lue depuis stdin +aucun env requis +URI jamais imprimée +``` + +Statut : `TODO pre.008`. + +### V32-LIVE-002 — Non destructif + +Critères : + +```text +refus si metadata table préexiste +aucune base/schema drop +aucune table métier créée +cleanup seulement de metadata créée par le test +``` + +Statut : `TODO pre.008`. + +### V32-LIVE-003 — Scénario foundation + +Preuves : + +```text +connect +bootstrap initial +bootstrap idempotent +bootstrap concurrent +checksum mismatch +failure rollback +health ready +close borné +``` + +Statut : `TODO pre.008/pre.010`. + +### V32-LIVE-004 — PostgreSQL support + +Critère : test refuse major < 15 et enregistre seulement le major safe réellement testé. + +Cible release : PostgreSQL 18.6. + +Statut : `TODO pre.008/pre.010`. + +## 11. Security/adversarial + +### V32-SEC-001 — URI hostile + +Cas : vide, surdimensionnée, malformed, paramètres conflictuels, password contenant contrôles/URL-like. + +Attendu : rejet borné sans echo. + +Statut : `TODO pre.009`. + +### V32-SEC-002 — Secret canary + +Injecter un canary dans URI/password et prouver son absence de : + +```text +Debug +Display +ErrorContext +tracing snapshots +health snapshots +``` + +Statut : `TODO pre.009`. + +### V32-SEC-003 — Timeouts hostiles + +Cas : zéro, inversion, dépassement bornes pour pool/connect/migration/close. + +Statut : `TODO pre.003/pre.005/pre.009`. + +### V32-SEC-004 — Feature mismatch avant I/O + +Statut : `TODO pre.003/pre.009`. + +### V32-SEC-005 — Server error sanitization + +Un serveur/test double qui renvoie un message contenant un canary ne doit pas le faire traverser l'erreur publique. + +Statut : `TODO pre.005/pre.009`. + +## 12. Gates Rust/workspace + +À chaque tranche applicable : + +```bash +cargo fmt --all +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.2 +cargo check --workspace +cargo clippy --workspace --all-targets +``` + +Après création des crates : + +```bash +cargo test -p ksp-store-api +cargo test -p ksp-store-lib +cargo test -p ksp-store-postgres-lib +cargo test -p ksp-config-lib +cargo check -p ksp-store-lib --no-default-features +cargo tree -p ksp-store-lib --edges normal +cargo tree -p ksp-store-lib -e features +cargo tree -p ksp-store-postgres-lib --edges normal +cargo tree --duplicates +``` + +Gate technique final : + +```bash +cargo test --workspace +``` + +Les builds Tauri ne sont requis que si `pre.004` modifie réellement les resources/packaging desktop de manière justifiant cette preuve, puis au gate final si la matrice de packaging l'exige. + +Statut global : `TODO` jusqu'aux preuves de chaque tranche. + +## 13. Critères de fermeture + +La matrice ne peut passer en finale que si tous les critères applicables sont `PASS` et que : + +```text +aucun RawTransaction PostgreSQL +aucun RawAccountState PostgreSQL +aucun SQL métier RAW +aucune policy worker/job dans Store +aucune fuite backend dans façade +aucune lecture env par Store/backend +PostgreSQL live vert +workspace/clippy/tests verts +``` + +La réconciliation finale de cette matrice appartient à la prerelease documentaire précédant la lane de publication.