Commit graph

4 commits

Author SHA1 Message Date
oskar c65f0f2075 feat(kb-mail): adapter IMAP + model stanu synca + migracja 005
Krok 7 fazy mailowej, warstwa wspoldzielona. Realizuje decyzje (a), (b), (f)
reconu kb/audits/mail-sync-2026-08-06.md (zatwierdzone przez operatora
2026-08-06): jeden adapter IMAP na oba konta, stan synca jako tabela w bazie.

Nowe moduly w packages/kb-mail:
- imap.py    — ImapAccount/ImapClient nad stdlib imaplib (zero nowych zaleznosci).
               Foldery otwierane READ-ONLY (EXAMINE) i pobierane przez BODY.PEEK[],
               zeby job nie ustawial \Seen na skrzynce operatora. Wybor folderu po
               atrybucie SPECIAL-USE, nigdy po nazwie — Gmail lokalizuje
               "[Gmail]/All Mail". search_from_uid filtruje zakres po stronie
               klienta, bo n:* zwraca ostatnia wiadomosc takze gdy przedzial pusty.
- sync_state.py — tabela mail_sync_state + czyste funkcje: plan_folder_sync
               (pierwszy tick / przyrost / uniewaznienie UIDVALIDITY) i
               contiguous_last_uid (kursor przesuwa sie tylko po nieprzerwanym
               ciagu sukcesow — bledna wiadomosc jest ponawiana, nie przeskakiwana).
- headers.py / message.py — parse_headers(+fallback) z gmail-header-backfill oraz
               message_id/parse_date/parse_attachments/eml_ref z gmail-bulk-import,
               przeniesione zamiast skopiowane. Klucz dedup musi pochodzic z jednej
               implementacji: kazdy insert przyrostowki trafia na 225 030 istniejacych
               id. Stare joby re-eksportuja te nazwy — ich CLI i testy bez zmian.

kb_mail.db.insert_envelope zwraca teraz command tag (+ rows_affected,
envelope_source) — bez tego nie da sie odroznic zwyklego duplikatu od kolizji
Message-ID miedzy kontami (recon §2.4).

Migracja 005_mail_sync_state.sql: addytywna, klucz (account, folder).

Testy: 285 passed (111 kb-mail w tym 37 adaptera IMAP na fake serwerze i 26
planera kursora; 174 istniejace suity jobow bez zmian po ekstrakcji).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 15:30:57 +02:00
oskar 4658089e21 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:58:46 +02:00
oskar 8cafd9917f feat(kb-postgres): migration 002_chunks.sql — document_chunk table
Krok 1 planu docs/kb/modules/05-faza2-plan.md §3/§6 (chunk-level embeddings,
1:N do envelope). Addytywna — 001_envelope.sql nietknięta (zweryfikowane
\d envelope po migracji: identyczny schemat + FK jako "Referenced by").

Schemat wg rekomendacji recon (§2 decyzja 1+2): osobna tabela (nie kolumna
w envelope, bo N-wartościowy chunking jest obowiązkowy przy dokumentach
>8k tokenów), embedding VECTOR(1024) pod bge-m3 (dense), HNSW cosine index,
kolumna `model` do trywialnego re-indexu przy zmianie modelu (kb-00 zasada
#1: indeks odtwarzalny). Idempotentna (CREATE TABLE/INDEX IF NOT EXISTS,
zweryfikowane podwójnym uruchomieniem na kb-postgres@PIHA — drugi run same
NOTICE "already exists, skipping").

Zastosowana na żywej bazie: ssh piha docker exec kb-postgres psql, po
potwierdzeniu SQL przez Oskara. \dt + \d document_chunk + \d envelope
zweryfikowane po migracji.

Testy: dopisane sanity-testy 002 do packages/kb-mail/tests/test_migration.py
(wzorzec 001 — statyczne assercje na treści SQL, bez DB), 13/13 zielone.

Co NIE jest częścią tego kroku (§3 planu, odłożone): entity/entity_link
(graf encji) — szkic na przyszłość, nie blokuje domknięcia modułu 5.

Co dalej (plan §6, poza zakresem tego kroku): ollama pull bge-m3 na SOLARII,
token API Paperless, jobs/gmail-header-backfill/, adapter Paperless→koperta,
chunking+embed job.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:13:13 +02:00
oskar 1666511475 feat(kb-mail): fundament — pgvector spine, koperta, archiwum, pakiet domeny
- services/kb-postgres: pgvector/pgvector:pg16 na SOLARIA (:5433), named
  volume, init/001_envelope.sql (CREATE EXTENSION vector + zamrożona tabela
  envelope: id/source/ts/geo/raw_ref/entities), service.yaml, healthcheck,
  README z poprawnym mechanizmem deploy (deploy-node.sh składa dwa -f)
- hosts/solaria/runtime/kb-postgres/docker-compose.override.yml: mem_limit 4g
- inventory/topology.yaml + hosts/solaria/services.yaml: kb-postgres wpisany
- packages/kb-mail: nowa konwencja shared lib (pip install /repo/packages/<lib>/)
  envelope.py — @dataclass Envelope, walidacja tz-aware ts
  db.py       — insert_envelope / get_envelope (asyncpg, ON CONFLICT DO NOTHING)
  archive.py  — save_eml append-only (asyncio.to_thread, FileExistsError na dup)
  tests: 15 unit pass + 5 integration (@pytest.mark.integration, wymaga KB_TEST_DSN)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 20:02:25 +02:00