# Delta 0.0.4-alpha.2 — owner PostgreSQL, pool et première migration ## Baseline requise Partir de `0.0.4-alpha.1` validée et historisée `PASS` : ```text version précédente 0.0.4-alpha.1 history requis history/0.0.4/alpha.1.md = PASS stable autoritaire v0.0.3 owner décidé knowledge-store-postgres-lib driver décidé tokio-postgres pool décidé deadpool-postgres migrator décidé Refinery ``` Le history `alpha.1` doit être committé et poussé avant application du présent delta. La version devient : ```text 0.0.4-alpha.2 ``` ## Objet Matérialiser la première frontière PostgreSQL réelle sans encore raccorder les launchers ou les cas d'usage applicatifs : - créer `knowledge-store-postgres-lib` comme unique owner PostgreSQL ; - ajouter `tokio-postgres 0.7.18` comme driver async natif avec uniquement la feature `runtime` ; - ajouter `deadpool-postgres 0.14.2` comme pool avec uniquement `rt_tokio_1` ; - ajouter Refinery `0.9.2` avec uniquement son support `tokio-postgres` ; - utiliser Tokio `1.53.1` uniquement comme runtime de test ; - recevoir URL PostgreSQL et taille du pool par configuration injectée ; - ne jamais lire de secret depuis l'environnement dans la crate produit ; - construire un pool borné et conserver `NoTls` comme choix initial explicite ; - embarquer `V1__initial_sources.sql` via Refinery ; - créer uniquement `knowledge_sources` et `knowledge_source_sync_state` ; - exposer une application explicite des migrations ; - prouver le chemin sur un PostgreSQL réel isolé par schéma temporaire. Git reste l'autorité du contenu publié. Cette tranche ne stocke ni corps de contenu, ni credential Git, ni compte, proposition, job, index ou projection finale. ## Dépendances retenues ```text tokio-postgres 0.7.18 default-features = false, features = ["runtime"] deadpool-postgres 0.14.2 default-features = false, features = ["rt_tokio_1"] refinery 0.9.2 default-features = false, features = ["tokio-postgres"] tokio 1.53.1 dev only, features = ["macros", "rt-multi-thread"] ``` Aucun ORM, TLS backend supplémentaire ou abstraction multi-SGBD n'est introduit. ## Contrat public La façade crate-root est limitée à : ```text PostgresStoreConfig PostgresStore PostgresStoreError ``` Les types `tokio-postgres`, Deadpool et Refinery restent privés à l'implémentation. `PostgresStoreConfig` ne fournit aucun getter public de l'URL et n'implémente volontairement pas `Debug`. L'URL peut contenir des credentials et ne doit pas être exposée dans les erreurs ou logs. ## Premier schéma ```text knowledge_sources source_id TEXT PRIMARY KEY family TEXT NOT NULL CHECK pgr/howto/snippet/project_local git_reference TEXT NOT NULL knowledge_source_sync_state source_id TEXT PRIMARY KEY REFERENCES knowledge_sources ON DELETE CASCADE last_synchronized_revision TEXT NOT NULL ``` Refinery possède sa table technique de suivi des migrations. Aucune autre table métier n'est créée. ## Scope des fichiers REPLACE : ```text VERSION Cargo.toml README.md RULES.md docs/architecture/001-PROJECT_PROFILE.md docs/architecture/002-KNOWLEDGE_ARCHITECTURE.md docs/plans/004-V0_0_4_POSTGRES_FOUNDATION_PLAN.md docs/studies/008-V0_0_4_POSTGRES_FOUNDATION_STUDY.md docs/validation/001-VALIDATION_MATRIX.md ``` ADD : ```text crates/knowledge-store-postgres-lib/Cargo.toml crates/knowledge-store-postgres-lib/src/lib.rs crates/knowledge-store-postgres-lib/src/config.rs crates/knowledge-store-postgres-lib/src/error.rs crates/knowledge-store-postgres-lib/src/store.rs crates/knowledge-store-postgres-lib/unit_tests/config.rs crates/knowledge-store-postgres-lib/tests/postgres_migration.rs crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql deltas/0.0.4/alpha.2.md ``` DELETE : aucun. Aucun fichier sous `Web/`, les trois launchers, `knowledge-app-lib`, `knowledge-domain-lib`, `knowledge-git-api`, `knowledge-git-lib` ou `knowledge-sync-api` n'est modifié. Aucun history `0.0.4-alpha.2` n'est inclus : il doit refléter uniquement la gate opérateur réelle. ## Précondition PostgreSQL de la gate La gate réelle nécessite une base PostgreSQL de test accessible avec les droits de créer et supprimer un schéma. Fournir l'URL uniquement dans l'environnement opérateur : ```bash export KNOWLEDGE_POSTGRES_TEST_URL='postgresql://...' ``` Ne jamais versionner cette valeur. Si `KNOWLEDGE_POSTGRES_TEST_URL` est absent ou si PostgreSQL n'est pas joignable, arrêter la gate et classer la tranche `BLOCKED`. Ne pas convertir cette absence en `PASS` ou en test ignoré. ## Gate opérateur Exécuter depuis la racine du dépôt après application du delta. ### Version, history précédent et scope ```bash test "$(cat VERSION)" = '0.0.4-alpha.2' grep -F 'version = "0.0.4-alpha.2"' Cargo.toml test -f history/0.0.4/alpha.1.md grep -A2 '^## Statut$' history/0.0.4/alpha.1.md | grep -Fx 'PASS' git ls-files --error-unmatch history/0.0.4/alpha.1.md >/dev/null test -z "$(git status --short -- history/0.0.4/alpha.1.md)" test -d crates/knowledge-store-postgres-lib test -f crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql test -f deltas/0.0.4/alpha.2.md test ! -e history/0.0.4/alpha.2.md test -z "$(git status --short -- Web crates/knowledge-pgr-server crates/knowledge-howtos-server crates/knowledge-snippets-server crates/knowledge-app-lib crates/knowledge-domain-lib crates/knowledge-git-api crates/knowledge-git-lib crates/knowledge-sync-api)" git diff --check ``` ### Dépendances, façade et configuration ```bash grep -F 'tokio-postgres = { version = "0.7.18", default-features = false, features = ["runtime"] }' crates/knowledge-store-postgres-lib/Cargo.toml grep -F 'deadpool-postgres = { version = "0.14.2", default-features = false, features = ["rt_tokio_1"] }' crates/knowledge-store-postgres-lib/Cargo.toml grep -F 'refinery = { version = "0.9.2", default-features = false, features = ["tokio-postgres"] }' crates/knowledge-store-postgres-lib/Cargo.toml grep -F 'tokio = { version = "1.53.1", default-features = false, features = ["macros", "rt-multi-thread"] }' crates/knowledge-store-postgres-lib/Cargo.toml test "$(grep -c '^pub use crate::' crates/knowledge-store-postgres-lib/src/lib.rs)" -eq 3 grep -Fx 'pub use crate::config::PostgresStoreConfig;' crates/knowledge-store-postgres-lib/src/lib.rs grep -Fx 'pub use crate::error::PostgresStoreError;' crates/knowledge-store-postgres-lib/src/lib.rs grep -Fx 'pub use crate::store::PostgresStore;' crates/knowledge-store-postgres-lib/src/lib.rs ! grep -R -n -E 'std::env|KNOWLEDGE_POSTGRES_TEST_URL' crates/knowledge-store-postgres-lib/src ! grep -R -n -E 'println!|eprintln!|dbg!' crates/knowledge-store-postgres-lib/src grep -F 'max_pool_size' crates/knowledge-store-postgres-lib/src/config.rs grep -F 'deadpool_postgres::Manager::new' crates/knowledge-store-postgres-lib/src/store.rs grep -F 'deadpool_postgres::Pool::builder' crates/knowledge-store-postgres-lib/src/store.rs grep -F 'tokio_postgres::NoTls' crates/knowledge-store-postgres-lib/src/store.rs grep -F 'run_async(client)' crates/knowledge-store-postgres-lib/src/store.rs ``` ### Migration et test ciblé ```bash grep -F 'CREATE TABLE knowledge_sources' crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql grep -F "CHECK (family IN ('pgr', 'howto', 'snippet', 'project_local'))" crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql grep -F 'CREATE TABLE knowledge_source_sync_state' crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql grep -F 'REFERENCES knowledge_sources(source_id) ON DELETE CASCADE' crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql grep -F 'last_synchronized_revision TEXT NOT NULL' crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql ! grep -E -i '\b(content|body|credential|account|proposal|job)\b' crates/knowledge-store-postgres-lib/migrations/V1__initial_sources.sql grep -F '#[ignore = "requires KNOWLEDGE_POSTGRES_TEST_URL"]' crates/knowledge-store-postgres-lib/tests/postgres_migration.rs grep -F 'CREATE SCHEMA' crates/knowledge-store-postgres-lib/tests/postgres_migration.rs grep -F 'DROP SCHEMA' crates/knowledge-store-postgres-lib/tests/postgres_migration.rs ``` ### Markdown puis séquence Rust ```bash python3 -B scripts/audit_markdown_headers.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history python3 -B scripts/audit_markdown_links.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history python3 -B scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history cargo fmt --all cargo fmt --all -- --check python3 -B scripts/audit_rust_test_layout.py crates python3 -B scripts/audit_rust_blank_lines.py crates python3 -B scripts/audit_rust_item_spacing.py crates python3 -B scripts/audit_rust_module_order.py crates python3 -B scripts/audit_rust_trait_import_blocks.py crates python3 -B scripts/audit_rust_reexport_blocks.py crates python3 -B scripts/audit_rust_crate_root_facades.py crates python3 -B scripts/audit_rust_export_completeness.py --root . --summary-only cargo metadata --format-version 1 --no-deps > /tmp/sasedev-knowledge-0.0.4-alpha.2-metadata.json cargo check --workspace cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test -p knowledge-store-postgres-lib cargo test --workspace --all-targets --all-features ``` ### Composition workspace ```bash python3 -c 'import json; from pathlib import Path; m=json.loads(Path("/tmp/sasedev-knowledge-0.0.4-alpha.2-metadata.json").read_text()); expected={"knowledge-app-lib","knowledge-domain-lib","knowledge-git-api","knowledge-git-lib","knowledge-sync-api","knowledge-web-lib","knowledge-pgr-server","knowledge-howtos-server","knowledge-snippets-server","knowledge-store-postgres-lib"}; assert len(m["workspace_members"]) == 10; assert {p["name"] for p in m["packages"]} == expected; print("Knowledge 0.0.4-alpha.2 workspace audit: clean")' ``` ### PostgreSQL réel obligatoire ```bash test -n "${KNOWLEDGE_POSTGRES_TEST_URL:-}" cargo test -p knowledge-store-postgres-lib --test postgres_migration -- --ignored --nocapture ``` Si la première commande échoue ou si le test ne peut pas joindre PostgreSQL, arrêter ici et reporter `BLOCKED` avec le transcript obtenu. ### Hygiène, lockfiles et staging ```bash python3 -c 'from pathlib import Path; roots=[Path("README.md"),Path("RULES.md"),Path("ROADMAP.md"),Path("CHANGELOG.md"),Path("Cargo.toml"),Path("VERSION"),Path("docs"),Path("prompts"),Path("deltas"),Path("history"),Path("crates")]; allowed={".md",".rs",".toml",".sql"}; paths=[p for r in roots for p in ([r] if r.is_file() else r.rglob("*")) if p.is_file() and (p.name == "VERSION" or p.suffix in allowed)]; bad=[str(p) for p in paths if (lambda b: b"\r" in b or not b.endswith(b"\n") or b.endswith(b"\n\n") or any(line != line.rstrip(" \t") for line in b.decode("utf-8").splitlines()))(p.read_bytes())]; assert not bad, bad; print(f"Knowledge 0.0.4-alpha.2 text hygiene: clean ({len(paths)} file(s))")' test -f Cargo.lock git check-ignore -q Cargo.lock if git ls-files --error-unmatch Cargo.lock >/dev/null 2>&1; then echo 'Cargo.lock must remain untracked for Knowledge' >&2; exit 1; fi test -f Web/knowledge-template-lab/package-lock.json git diff --quiet -- Web/knowledge-template-lab/package-lock.json git add -A git diff --cached --check git status --short ``` ## Transition ### PASS Produire séparément : ```text history/0.0.4/alpha.2.md ``` avec les résultats réellement observés. Après application du history, commit/push `0.0.4-alpha.2`, puis préparer `0.0.4-alpha.3` pour la persistance minimale de source et d'état de synchronisation. ### FAIL Produire le history réel et le committer avant correction. Une erreur bornée de code, manifest, migration ou test utilise `0.0.4-alpha.2.fix.1`. ### BLOCKED Si seul le PostgreSQL réel requis est indisponible, historiser `BLOCKED` sans prétendre que la gate a passé. Ne modifier ni le code ni l'architecture tant qu'aucun défaut n'est démontré ; reprendre la même preuve dès qu'un PostgreSQL de test est disponible. ### REPLAN Replanifier si la toolchain stable réellement utilisée est incompatible avec les versions retenues, si l'isolation par schéma n'est pas fiable ou si l'ownership PostgreSQL doit être changé.