---
okf: "0.1"
type: session-log
visibility: private
status: active
updated: 2026-06-26
links: []
---

# 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:<pw>@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.)
