homelab-codex-ws/docs/sessions/2026-06-17-kb-foundations.md
oskar 01db57ab82 fix(kb): przepiecie wszystkich odwolan wewnetrznych po migracji
126 plikow (md, yaml, sh, py) odwolywalo sie do sciezek sprzed migracji.

  15  markdown-linkow [..](..) -> policzona sciezka WZGLEDNA wobec pliku
      odsylajacego (wczesniej czesc z nich byla repo-root-relative i nie
      rozwiazywala sie z katalogu, w ktorym lezala)
 200  odwolan tekstowych (backticki, proza, yaml, importy w kodzie)
      -> nowa sciezka repo-root-relative, zgodnie z konwencja repo
   5  linkow rodzenstwa (gole nazwy plikow, np. "](DEPLOY.md)") — dzialaly
      tylko w starym katalogu; przeliczone recznie

Objete m.in.: CLAUDE.md (scripts/onboard/README.md -> kb/runbooks/
node-onboarding-tool.md, docs/backlog.md -> kb/phases/backlog.md),
README.md, .claude/skills/, 20 session logow, kod jobow.

Ostatnie 5 odwolan pochodzi z tresci wciagnietej rebasem z origin/master
(session log 2026-07-31, override node-agenta na SOLARII, dwie pozycje
backlogu) — wskazywaly na docs/incidents/, docs/kb/modules/ i
services/narty27/README.md sprzed migracji.

Dodany wzajemny link miedzy kb/services/control-plane.md (stub kodu)
a kb/subsystems/control-plane.md (opis, deprecated) — dwa dokumenty o tym
samym systemie, latwe do pomylenia.

Weryfikacja na 790 plikach: 0 odwolan do starych sciezek,
0 martwych linkow markdown. Lint OKF: 190/190 plikow ZGODNE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:53:57 +02:00

5.6 KiB
Raw Blame History

okf type visibility status updated links
0.1 session-log private active 2026-06-17

Sesja 2026-06-17 — KB foundations (etap 1 maili)

Cel

Zbudowanie fundamentu filaru maili: pgvector spine na SOLARIA, zamrożona koperta, pakiet domeny kb-mail, testy. Bez live ingestu, bez bulk Gmaila, bez indexera — sam fundament pod kolejne etapy.


Architektura KB — ustalona w tej sesji (docs)

4 warstwy × 4 filary + rdzeń

[ 4. Agent interdyscyplinarny ]   NL query + analityka (LLM)         ← wspólne
[ 3. Join + Enrich ]   entity resolution · graf · OwnTracks           ← wspólne
[ 2. Preprocess + Index ]   → pgvector / → SQL                        ← per filar
[ 1. Ingest ]   Maile  Dokumenty  Zdjęcia  Transakcje                 ← per filar

OwnTracks = klucz czasoprzestrzenny w warstwie 3, nie osobny filar (ciągła funkcja czas→miejsce).

Decyzje zamknięte

  • Spine: Postgres + pgvector (nie Qdrant) na SOLARIA
  • Embed: bge-m3 (multilingual, długi kontekst, lepszy pod polski)
  • Maile: dwa żywe źródła — Fastmail (JMAP, primary) + Gmail (IMAP; konto zostaje jako śmieciowe/2FA)
  • Bulk historyczny Gmail (jednorazowy) — etap 2
  • Reguła: archiwizuj wszystko, indeksuj selektywnie (filtr na wejściu do indeksu, nie archiwum)
  • Załączniki: II tura (MVP = czysty tekst + nagłówki)
  • Warstwa 3 startuje jako cienki graf encji; federacja przy zapytaniu — później
  • Dokumenty: Nextcloud (drive, WebDAV) + Paperless-ngx (skany/faktury/OCR)
  • Koperta: zamrożona addytywna — id / source / ts(UTC) / geo / raw_ref / entities[]

Decyzje otwarte

  • Transakcje (filar #4): OPEN ISSUE — agregator PSD2 (GoCardless / Tink) dla mBank + Revolut, ale zgoda SCA wygasa co 90 dni → brak pełnego bezobsługowego sync; fallback: CSV/MT940. Do decyzji przy starcie filaru #4.

Etap 1 — ZBUDOWANY

services/kb-postgres

  • Obraz: pgvector/pgvector:pg16
  • SOLARIA, port 5433 (5432 zarezerwowany na potencjalny lokalny postgres)
  • Named volume: kb_postgres_data
  • Init SQL (init/001_envelope.sql): CREATE EXTENSION vector + tabela envelope
  • Per-host override: hosts/solaria/runtime/kb-postgres/docker-compose.override.ymlmem_limit: 4g
  • inventory/topology.yaml + hosts/solaria/services.yaml — wpisy dodane

Zamrożona koperta (001_envelope.sql + Envelope dataclass)

CREATE TABLE envelope (
    id       TEXT PRIMARY KEY,
    source   TEXT NOT NULL,       -- fastmail | gmail | ...
    ts       TIMESTAMPTZ NOT NULL,
    geo      JSONB,               -- null dla maili; warstwa 3 uzupełnia
    raw_ref  TEXT NOT NULL,       -- ścieżka do .eml w archiwum
    entities JSONB NOT NULL DEFAULT '[]'
);

Envelope dataclass waliduje ts.tzinfo is not None w __post_init__.

packages/kb-mail — nowa konwencja shared lib

Lokalizacja: packages/<lib>/ (nie services/) — biblioteki reużywalne przez joby. Instalacja w Dockerfile: COPY packages/kb-mail/ /packages/kb-mail/ && pip install /packages/kb-mail/.

Moduł Co robi
envelope.py @dataclass Envelope, walidacja tz-aware ts
db.py insert_envelope (ON CONFLICT DO NOTHING) + get_envelope (asyncpg)
archive.py save_eml — append-only, asyncio.to_thread na write, FileExistsError na duplikat

structlog JSON w każdym module (structlog.get_logger(__name__)); konfiguracja po stronie konsumenta (biblioteka nie konfiguruje structlog).

Testy

  • 15 unit testów (nie-integration): model, archiwum, sanity SQL — wszystkie zielone bez DB
  • 5 integration testów (@pytest.mark.integration): round-trip DB, duplikat, geo, entities — wymagają KB_TEST_DSN
  • conftest.py: fixture db_conn = asyncpg connection + BEGIN/ROLLBACK na każdy test

Poprawki spójności (code-review sesji)

  1. README deploy: pierwotna wersja miała docker compose --env-file /opt/homelab/config/… — pomijała override file i miała złą ścieżkę. Naprawiono: README dokumentuje trzy ścieżki (standardowa przez deploy.sh solaria, first-time setup .env obok compose file, manual z dwoma -f), zgodnie z deploy-node.sh L6572.
  2. .gitignore: reguła *.env (L3) już łapie services/kb-postgres/.env — potwierdzono git check-ignore. Nic nie dodano.

Higiena git

  • Cała praca w worktree task/kb-foundations — master czysty przez cały czas
  • 2 commity na branchu po zakończeniu sesji

Commits

31c64d5 feat(kb-mail): fundament — pgvector spine, koperta, archiwum, pakiet domeny
<docs-commit> docs(kb): etap 1 fundament done + session log 2026-06-17

Files changed (etap 1)

services/kb-postgres/docker-compose.yml
services/kb-postgres/service.yaml
services/kb-postgres/env.example
services/kb-postgres/healthcheck.sh
services/kb-postgres/init/001_envelope.sql
kb/services/kb-postgres.md
hosts/solaria/runtime/kb-postgres/docker-compose.override.yml
hosts/solaria/services.yaml
inventory/topology.yaml
packages/kb-mail/pyproject.toml
packages/kb-mail/src/kb_mail/{__init__,envelope,db,archive}.py
packages/kb-mail/tests/{conftest,test_envelope,test_archive,test_db,test_migration}.py
kb/subsystems/kb-overview.md   (etap 1 done, konwencja packages/)
CLAUDE.md                   (sekcja Shared Python Libraries)
docs/sessions/2026-06-17-kb-foundations.md

Następny krok

Etap 2: jednorazowy bulk importer Gmail — mbox/Takeout → archiwum. Wejście: plik .mbox lub katalog Maildir z eksportu Google Takeout. Wyjście: .eml w archiwum + wiersze envelope w DB. Jako one-shot job (nie serwis), reużywa packages/kb-mail.