diff --git a/docs/kb/kb-00-overview.md b/docs/kb/kb-00-overview.md index a48a0a5..e735145 100644 --- a/docs/kb/kb-00-overview.md +++ b/docs/kb/kb-00-overview.md @@ -131,13 +131,16 @@ Pierwszy job: `jobs/gmail-bulk-import/` — jednorazowy bulk importer Gmail Take - ✅ deploy na PIHA: kontener healthy, schemat `envelope` + extension `vector` zweryfikowane - ⏳ zostaje: transfer archiwum/.eml na PIHA NVMe (docelowo), poprawka `KB_TEST_DSN` (solaria→piha) w testach -~~Etap 2b: jednorazowy bulk importer Gmail (mbox/Takeout → archiwum).~~ **KOD GOTOWY** (2026-06-24) — nie uruchomiony. +~~Etap 2b: jednorazowy bulk importer Gmail (mbox/Takeout → archiwum).~~ **URUCHOMIONY** (2026-06-25). - ✅ `jobs/gmail-bulk-import/` — CLI importer bez Dockera (pip install -e na PIHA) - ✅ entities[]: manifest załączników (filename, content_type, size, sha256) od dnia zero - ✅ batch inserty, idempotentny, --limit, epoch_fallback, statystyki załączników - ✅ 24 testy jednostkowe, wszystkie zielone -- ⏳ Google Takeout ~27 GB mbox — do transferu SOLARIA→PIHA + uruchomienia +- ✅ Pełny import uruchomiony na PIHA (~29 min): **225 030 unikalnych kopert**, **27 GB archiwum .eml**, manifest **70 193 załączników** -**Następny krok**: transfer Takeout SOLARIA→PIHA (rsync Tailscale) → dry-run → próbka --limit 200 → pełny wlew `ionice -c 3 nice -n 19`. -Szczegóły kolejności: `kb-01-email-design.md` §8. +**Backlog / następne kroki**: +- Faza 2 załączników: ekstrakcja/OCR (PDF/skany → Paperless lub dedykowany job) +- Odzysk 2559 dat epoch-fallback z nagłówków `Received:`/`X-GM-RECEIVED` +- Etap 3: Fastmail JMAP live ingest → `jobs/fastmail-poller/` +- Etap 4: Gmail IMAP live sync → `jobs/gmail-imap-poller/` diff --git a/docs/sessions/2026-06-25-kb-gmail-import-uruchomiony.md b/docs/sessions/2026-06-25-kb-gmail-import-uruchomiony.md new file mode 100644 index 0000000..93d7ced --- /dev/null +++ b/docs/sessions/2026-06-25-kb-gmail-import-uruchomiony.md @@ -0,0 +1,144 @@ +# Sesja 2026-06-25 — KB etap 2: bulk import Gmail uruchomiony + +## Cel + +Domknięcie etapu 2 bazy wiedzy. Poprzednia sesja (2026-06-24) zostawiła kod gotowy, +ale dane na SOLARIA. Ta sesja = transfer + uruchomienie + weryfikacja na produkcji (PIHA). + +--- + +## Co zrobione + +### Relokacja kb-postgres SOLARIA→PIHA — domknięta i zweryfikowana + +Baza stoi na PIHA (always-on); zapytania KB działają 24/7 niezależnie od SOLARIA. + +### Przygotowanie PIHA pod import + +- **cgroup memory enable**: `cgroup_enable=memory cgroup_memory=1` dopisane do + `/boot/firmware/cmdline.txt` + reboot; backup w `cmdline.txt.bak`. +- **Swap 4 GB**: wpisany do `/etc/fstab` (był już skonfigurowany wcześniej, weryfikacja). +- **SSH key perms**: `chmod 600 ~/.ssh/id_rsa` — prawa `0640` blokowały `git fetch` + (OpenSSH odrzuca klucze `group-readable`). + +### Transfer Takeout SOLARIA→PIHA + +`rsync` po LAN (nie Tailscale, oba dostępne): 15 GB zip → po rozpakowaniu +**27 GB `allmail.mbox`** wylądowało w `~/kb/dropbox/`. +`venv` pod PEP668 w `~/kb/venv` (Pi OS wymusza brak systemowych pip-instalacji). + +### Walidacja przed pełnym wlewem + +1. `--dry-run --limit 200` — parsowanie bez zapisów, weryfikacja nagłówków. +2. `--limit 1000` z realnym zapisem — próbka; potwierdzono że RAM stoi płasko: + zużycie to koszt zbudowania indeksu `mailbox.mbox` przy otwarciu, nie akumulacja + per-mail w pętli. + +### Pełny import + +```bash +nohup nice -n 15 ionice -c2 -n7 \ + gmail-bulk-import \ + --mbox ~/kb/dropbox/allmail.mbox \ + --archive ~/kb/mail/archive \ + --dsn postgresql://kb:@localhost:5433/kb \ + >> ~/kb/import.log 2>&1 & +``` + +Czas: **~29 minut**. Brak OOM, swap stabilny przez cały przebieg. + +--- + +## Wynik importu + +| Metryka | Wartość | +|---------|---------| +| processed | 226 318 | +| imported (pliki .eml) | 225 057 | +| skipped (duplikaty Message-ID) | 1 260 | +| errors (zepsute maile) | 1 | +| epoch_fallback (brak daty) | 2 559 | +| msgs_with_attachments | 32 495 | +| total_attachments | 70 193 | +| total_attachment_bytes | 15,4 GB | + +**Baza (envelope):** `SELECT count(DISTINCT id) FROM envelope` → **225 030** unikalnych kopert. +**Archiwum:** 225 057 plików `.eml`, **27 GB na NVMe PIHA** (`~/kb/mail/archive`). +**Zakres dat:** 2002→2026-06-19; pik 2011–2012 (~23 k/rok); bez dziur. + +--- + +## Lekcje + +### `imported` ≠ wiersze w DB — NORMA, nie bug + +Importer liczy `imported` jako zapisane pliki `.eml`. +`count(DISTINCT id)` w `envelope` jest mniejsze o duplikaty Message-ID: +`ON CONFLICT (id) DO NOTHING` je poprawnie odrzuca. + +Różnica: 225 057 archiwum − 225 030 DB = **27 duplikatów klucza** — zero utraty danych. + +Zmarnowano ~30 minut na re-run całego mboxa szukając tych „27", zanim przeczytano kod +importera. **Reguła: verify-before-fix** — najpierw sprawdź co kod faktycznie robi, +zanim zaczniesz pisać fixa. + +### `mailbox.mbox` buduje indeks przy każdym otwarciu + +`python mailbox.mbox` skanuje całe 27 GB przed pierwszą wiadomością. +Na Pi5 to kilka minut startu — **nie zawis, nie błąd**. Re-run płaci ten koszt w całości +(wszystkie 226 k wiadomości przelatują ponownie przez idempotencję). +Jeśli trzeba dosłać kilka kopert, taniej będzie osobny skrypt niż re-run mboxa. + +### RAM/swap stabilne + +Swap ~47% podczas importu = stałe tło Home Assistant, nie skok od importera. +Hard `mem_limit: 1g` na kb-postgres chronił HA przez cały przebieg. + +--- + +## Sprzątanie po imporcie + +- `allmail.mbox` + oryginalny zip skasowane z `~/kb/dropbox/` na PIHA → odzysk **~42 GB NVMe**. +- Oryginalny zip Takeout (15 GB) przeniesiony na SOLARIA `~/kb/_cold/` jako cold backup + (do końca fazy 2, potem do skasowania). + +--- + +## Stan etapu 2 + +**ZAMKNIĘTY.** + +Pełna historia Gmaila 2002→2026 w bazie wiedzy: +- **225 030** unikalnych kopert w `kb-postgres` (PIHA) +- **27 GB** archiwum `.eml` (PIHA NVMe) +- manifest **70 193** załączników w `entities[]` (ekstrakcja/OCR = faza 2) + +--- + +## Backlog / następne kroki + +- **Faza 2 załączników**: ekstrakcja i OCR (PDF/skany → Paperless lub dedykowany job). +- **Odzysk 2559 dat epoch-fallback**: nagłówki `Received:` / `X-GM-RECEIVED` mogą dać + prawdziwe timestamps dla maili bez `Date:`. +- **Etap 3**: Fastmail JMAP live ingest → `jobs/fastmail-poller/`. +- **Etap 4**: Gmail IMAP live sync → `jobs/gmail-imap-poller/`. + +--- + +## Higiena git + +Praca w worktree `task/kb-session-0625`; główny checkout `~/homelab-codex-ws` czysty. + +--- + +## Commits tej sesji + +``` +c0ffb6a docs(kb): sesja 2026-06-22 — spine relokowany na PIHA + przygotowanie hosta +c32e050 docs(kb): sesja 2026-06-24 — importer Gmail gotowy + konwencja jobs/ +254a680 fix(piha): capabilities — realny RAM/NVMe + gitignore build dirs +f234280 refactor(kb-mail): importer Gmail — entities załączników, --limit, batch, bez Dockera, DSN→PIHA +6dc1d32 feat(kb-mail): etap 2 — jednorazowy bulk importer Gmail (mbox → archiwum) +``` + +(Commitów implementacyjnych w tej sesji brak — dokumentacja domknięcia etapu 2.)