homelab-codex-ws/docs/sessions/2026-07-16.md

9.5 KiB
Raw Blame History


Wątek KB — krok 7 (pilot retrieval) + GPU: FAZA 2 MODUŁU 5 DOMKNIĘTA

GPU przywrócone: sekcja deploy w compose odkomentowana (merge ollama-gpu-restore), recreate, bge-m3 na 100% GPU. Benchmark: 207ms/embed vs 790ms CPU (~3.8× sekwencyjnie) — overhead HTTP dominuje przy pojedynczych requestach, batching pozostaje dźwignią (backlog, przed fazą mailową). Zagadka znikającego kontenera po reboocie 15.07: jednorazowa, po boocie 16.07 wszystko wstało samo.

Krok 7 — pilot retrieval (2683 chunki, zapytania przez bge-m3 + <=> cosine):

  • Kalibracja progów: <0.45 trafienie, 0.450.55 szara strefa, >0.55 brak odpowiedzi (negatywna kontrola "sernik" = 0.62, czysta separacja)
  • Cross-lingual potwierdzony: angielskie zapytanie o FLL scoring lepsze niż polskie, wyciąga scoresheet mimo mojibake
  • Najlepszy wynik: "innovation project scoring" → 0.387, top-5 spójnie z właściwego dokumentu
  • Chunking 600/150 zatwierdzony bez zmian
  • Findings do fazy 3 (nieblokujące): filtr chunków z binarnym OCR-szumem (przed kompilacją wiki!), deduplikacja dokumentów (paperless:14 ≡ 74), jakość OCR scoresheets

Faza 2 modułu 5: kroki 18 komplet. Baza: 225 216 kopert (gmail+paperless, cross-source), 2683 chunki z embeddingami, retrieval zweryfikowany. Następne: faza 3 — recon-plan (streszczenia+tagi jako pierwszy krok kompilacji, docelowo wiki-kompilat wg Karpathy'ego; Claude ma przygotować szkic sekcji wiki do recon-planu).


Wątek control-plane — druga połowa dnia: "czemu supervisor nie generuje akcji naprawczych"

Punkt wyjścia: pytanie operatora o pustą kolejkę akcji odsłoniło wielowarstwową awarię warstwy decyzyjnej control-plane. Cztery kolejne fixy, każdy odkrywał następną warstwę:

1. RECON lustro shipping (Fable, commit 542bba4)

docs/infra/lustro-shipping-recon-2026-07-16.md — 1507 mismatchy lustro event=dead prom=up w trwałym logu WYJAŚNIONE: (a) wczorajszy kontrolowany test (node-agent stał 3h20m, nie 15 min jak zakładano) + (b) poranny boot-race 56s. Werdykt: shipping lustro działa, ZERO recurring problemu. Prometheus 0 pomyłek w 48h — wzmacnia rekomendację GO dla Etapu 3 cutoveru.

Znaleziska poboczne: lustro biega na obrazie sprzed 5 tyg (deploy-node bez --build — patrz fix #2 niżej); fake-hwclock boot-race (RPi bez RTC — pierwszy event po boocie ma stary stempel, dropnięty przez timestamp checkpoint).

2. FIX deploy-node.sh --build (commit 77defff)

deploy-node.sh robił docker compose up -d BEZ --build → dla serwisów z Dockerfile zmiany kodu NIE wchodziły (cicha rozbieżność repo↔runtime — backlog item z 2026-07-15, dziś naprawiony). Ugryzło 3×: fleet-prometheus, ha-diag, lustro.

Fix: warunkowy --build gdy serwis ma Dockerfile (test -f services/<svc>/Dockerfile), prebuilt bez --build. Zweryfikowany w boju na PIHA (6 serwisów: node-agent/ha-diag/brain-watchdog/llm-gateway → Building; vikunja/kb-postgres → prebuilt).

Edge case zgłoszony jako follow-up: agent-system ma build w podkatalogach bez top-level Dockerfile (niezarejestrowany w tej detekcji).

3. FIX supervisor resilience (commit 409b583)

Supervisor był funkcjonalnie zamrożony ~24h — kontener healthy, ale pętla nie tikała, zero logów. Root cause zweryfikowany na /proc (proces State:S hrtimer_nanosleep, NIE deadlock): reconcile() robi glob po EVENTS_DIR co cykl, a to 358k plików → cykl przekracza timeout → nigdy się nie kończy. Plus logi na DEBUG = niewidoczne.

Fix: każdy cykl w ThreadPoolExecutor z future.result(timeout=90s, env SUPERVISOR_RECONCILE_TIMEOUT); try/except owija cykl (wyjątek nie zabija pętli); tick-log co 10 cykli (env SUPERVISOR_TICK_LOG_EVERY) na INFO; healthcheck sprawdza świeżość heartbeat (nie samo że proces żyje). Zdeployowany. Po deployu: pętla tika (cycle #340→#480), cykl #1 timeoutował (ERROR "did not complete within 90s") ale pętla szła dalej = odporność działa.

4. FIX event flood + retencja + cleanup (commit dff76ec) — sedno problemu

Root cause braku akcji: EVENTS_DIR = 358k plików, 91% to service_healthy (szum "serwis zdrowy" emitowany co cykl per serwis).

Krytyczne odkrycie: mechanizm retencji _cleanup_control_plane_fs() był martwy od wczorajszego fixu checkpointu (d5139c9, 2026-07-15) — kod porównywał str(ścieżka) <= checkpoint_intTypeError cicho łapany przez except → retencja przestała działać → backlog rósł bez ograniczenia. Naprawiając checkpoint wczoraj, złamaliśmy retencję, która na nim polegała.

Fix:

  • (a) node-agent emituje service_healthy TYLKO na transition unhealthy→healthy (nie co cykl) — funkcja zachowana: observer.process_event nadal konsumuje service_healthy do services.json[key].status=healthy + rozwiązuje incydent, więc nie wycięte, tylko ograniczone do transition;
  • (b) retencja naprawiona epoch-do-epoch (ta sama logika co _checkpoint_ts_from_value);
  • (c) skrypt scripts/maintenance/cleanup_event_backlog.py (dry-run + --apply, min_age 3600s, kasuje tylko service_healthy/node_health starsze niż checkpoint, zachowuje healthcheck_failed/incydenty/wszystkie sygnały).

150 testów pass. Zdeployowany node-agent na PIHA+VPS. Cleanup wykonany: usunięto 272 232 pliki, backlog 358k→12,7k. Ghost dir be17cb6eb0f6 usunięty. Wynik: reconcile supervisora przestał timeoutować (0 "did not complete" w 5 min), glob 12,7k, mózg odetkany.

Stan końcowy

Control-plane supervisor odblokowany (tika, reconcile się kończy, retencja działa automatycznie co cykl). Ale kolejka akcji nadal pusta — bo (a) shadow_mode=True downgrade'uje HA container_restart do alert_only, (b) wpisy error w topologii to ghost hash-prefixed w world_state observera (NIE żywe kontenery — docker ps -a exited=0 na VPS), observer nie czyści wpisów po zniknięciu kontenerów.

Lekcje

  • Cichy efekt uboczny migracji typów. Fix checkpointu d5139c9 (ścieżka→epoch int) cicho zepsuł retencję _cleanup_control_plane_fs(), bo ta porównywała str <= int i łapała TypeError w szerokim except. Migracja typu pola musi audytować WSZYSTKICH konsumentów tego pola, nie tylko miejsce zmiany — szeroki except maskuje dokładnie tę klasę regresji.
  • "Healthy kontener ≠ tikająca pętla." Docker healthcheck sprawdzający tylko "czy proces żyje" nie łapie pętli zawieszonej na blokującym wywołaniu bez timeoutu. Healthcheck musi sprawdzać świeżość heartbeat/ostatniego cyklu, nie tylko czy proces odpowiada.
  • service_healthy jako plik-event per cykl to antywzorzec. Stan ("serwis jest zdrowy") emitowany jako zdarzenie na każdym cyklu miesza dwa różne pojęcia (stan vs zdarzenie) i skaluje się liniowo z (liczba serwisów × liczba cykli) — dokładnie to, co wygenerowało 358k plików. Emitować tylko na transition.
  • Równoległe sesje = ciągłe rozjazdy mastera. Kilka CC działających jednocześnie na różnych worktree podnosi ryzyko push divergence — dyscyplina "zatrzymaj się i zgłoś" przy konflikcie jest tańsza niż force-push.

Otwarte (następne sesje, osobne świadome tematy)

  • Ghost-wpisy w world_state observera (hash-prefixed error w topologii mimo 0 exited kontenerów — observer nie prune'uje zniknionych kontenerów ze stanu). To trzyma System Status: ERROR fałszywie.
  • shadow_mode → remediacja: decyzja czy włączyć auto-restart padłych kontenerów (architektura, guardraile, cooldowny).
  • Czemu supervisor nie generuje akcji redeploy mimo widocznych realnych error (elasticsearch/diskover na piha, ollama solaria) — drift→action nie domyka się.
  • gokapi .env not found (deploy-node VPS rzuca błąd na gokapi — brakujący .env).
  • Etap 3 cutover per-node (dane gotowe, recon GO).

Wątek KB — faza 3, krok 2 (migracja 004 + pilot streszczeń): W TOKU

Migracja 004 (document_summary) zastosowana na kb-postgres@PIHA: summary, tags JSONB, model, embedding+HNSW, UNIQUE z model (pozwala trzymać oba tory pilota jednocześnie).

Pilot dwutorowy (decyzja D3 planu):

  • Tor lokalny (gemma3:12b, GPU): 155/157 streszczeń + embeddingi. Po drodze realny bug: Ollama domyślnie ucina kontekst do ~2048 tok niezależnie od advertised 128k modelu — 71/157 dok. (45%) miało obcięte streszczenia (np. paperless:12 opisywał RODO zamiast treści AutoCasco, bo widział tylko pierwsze ~8k znaków). Naprawione: jawny num_ctx per wywołanie skalowany do długości treści + regression-guard w testach. Cały tor przeliczony od zera po fixie: 27 min na 157 dokumentów, zero CPU-offloadu (48/49 warstw GPU przez cały run).
  • Tor referencyjny (Claude Haiku 4.5, API): 157/157 streszczeń + embeddingi, koszt ~1.4 USD zgodny z szacunkiem. Klucz API przez plik poza repo, nigdy nie trafił do transkryptu, usunięty po użyciu.

Stan: commit 33f9944 na task/kb-f3-summaries (niezmergowany — worktree żyje, dokończenie w następnej sesji). Migracja + oba tory + fix num_ctx + testy gotowe.

Do zrobienia następnym razem (ten sam worktree): rebase na master (sąsiad wjechał w międzyczasie) → porównanie A/B ~15 dokumentów (Haiku vs gemma3, ocena przez Oskara) → weryfikacja końcowa (bilans, sanity SQL, retrieval po embeddingu streszczenia) → testy+commit+push → merge → decyzja o modelu dla fazy mailowej.

Lekcja do zapamiętania: każde wywołanie generatywne przez Ollamę musi jawnie ustawiać num_ctx — domyślna wartość runtime (~2048) cicho ucina długie dokumenty niezależnie od deklarowanego rozmiaru kontekstu modelu. Dotyczy też przyszłej syntezy w fazie 5.