homelab-codex-ws/kb/decisions/backlog-aktywne.md
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

32 KiB
Raw Permalink Blame History

okf type visibility status updated links
0.1 decision private active 2026-08-03
../phases/backlog.md

Aktywne

Bug upstreamu GoogleCloudPlatform/knowledge-catalog: generator grafu pomija linki od /

Data: 2026-07-31 Źródło: pilot fazy 5 — narty27 (docs/sessions/2026-07-31-kb-f4-final-narty27.md, sekcja „Wnioski do przeniesienia na fazę 5", pkt 3) Problem: generator grafu z knowledge-catalog pomija linki zaczynające się od / (ścieżki absolutne), wbrew §5.1 własnej spec OKF, która je dopuszcza. Efekt: część krawędzi grafu po prostu nie powstaje — cicho, bez ostrzeżenia. Rozbieżność implementacja↔spec po stronie upstreamu, nie naszej konfiguracji. Obejście (zastosowane): własny generator grafu (cytoscape) w pilocie narty27 — nie używamy generatora upstreamu. Fix: zgłosić issue/PR do GoogleCloudPlatform/knowledge-catalog (minimalny repro: dokument z linkiem /foo → brak krawędzi w wyjściu grafu, mimo §5.1). Jeśli upstream naprawi — rozważyć powrót z własnego generatora przy fazie 5 (wiki-kompilat), żeby nie utrzymywać własnego kodu bez potrzeby.


hosts/solaria/runtime/ollama/docker-compose.override.yml — brak w repo (rozjazd repo↔runtime)

Data: 2026-07-31 Źródło: sesja 2026-07-31 (docs/sessions/2026-07-31-kb-f4-final-narty27.md, sekcja „Otwarte po sesji" pkt 2) Problem: ollama jest zadeklarowana w hosts/solaria/services.yaml (rola llm-inference, exposure private = bind na TAILSCALE_BIND_IP + loopback), ale hosts/solaria/runtime/ zawiera wyłącznie node-agent i stability-agent — override dla ollama nie istnieje w repo. Host-specific konfiguracja żywego kontenera (rezerwacja GPU, bind, env) nie jest zatem wersjonowana: repo nie opisuje tego, co faktycznie biega na SOLARII. Ta sama klasa rozjazdu repo↔runtime co przy węzłach repo-less — dowolny redeploy z repo może wystawić serwis inaczej, niż działa dziś. Wzorzec docelowy istnieje obok: hosts/piha/runtime/ollama-piha/docker-compose.override.yml. Fix: zrekonstruować override z żywego kontenera na SOLARII (docker inspect → bind/porty/GPU/env/limity) i zacommitować jako hosts/solaria/runtime/ollama/docker-compose.override.yml; zweryfikować, że deploy z repo daje kontener identyczny z obecnym zanim ktokolwiek zrobi redeploy.


services/narty27: exposure: private w service.yaml + README vs faktyczna publiczna ekspozycja (NPM VPS + LE)

Data: 2026-07-31 Źródło: pilot fazy 5 — narty27 (docs/sessions/2026-07-31-kb-f4-final-narty27.md); znalezione przy porządkowaniu backlogu po tej sesji Problem: kontrakt serwisu deklaruje privateservices/narty27/service.yaml:5 (exposure: private # LAN/Tailscale only; no npm vhost, no public ingress) i to samo w kb/runbooks/narty27-deploy.md — podczas gdy narty27.kapala.org jest publiczne (NPM na VPS + cert Let's Encrypt). Pole exposure steruje traktowaniem ekspozycji przez agentów (patrz „Discovery Entry Points for Agents" w CLAUDE.md — service.yaml jest kontraktem operacyjnym, z którego agent czyta, jak zarządzać serwisem), więc rozjazd kontrakt↔rzeczywistość jest tu groźniejszy niż zwykła nieaktualna dokumentacja: agent podejmie decyzję na podstawie pola, które kłamie. Fix (osobny task): (1) najpierw zweryfikować, co realnie konsumuje pole exposure (observer / supervisor / ścieżka deployu) — dopiero to pokaże, czy poza dokumentacją zmiana coś przestawia; (2) potem poprawić service.yaml + README na public, z komentarzem wskazującym NPM VPS host #14 i cert LE #38.


scripts/ha/deploy.sh --delete: brak wspólnego toru kasacji automatyzacji

Data: 2026-07-27 Źródło: sesja porządków po audycie (task/ha-porzadki); kontekst bezpośredni: kasacja pkt 10 (36b43e5, para Tymka/powitanie-test/notify-router/para-prototyp) zrobiona pętlą ręcznych curl DELETE po API zamiast przez repo tooling. Problem: deploy.sh ma tylko WRITE (POST /api/config/<domain>/config/<id>) — zgodnie z DESIGN.md ("Deploy path") i istniejącym wpisem w tym backlogu (sekcja "Cutover HA ken", krok 4) DELETE obiektów usuniętych z repo jest poza zakresem, drift-check tylko ostrzega (warnings), nigdy nie kasuje. Efekt: jedyna droga usunięcia automatyzacji z żywej instancji to ręczne wywołanie API, bez drift-check/check_config/verify, czyli bez żadnej z gwarancji, które deploy.sh daje dla write. Fix: deploy.sh <instance> --delete <plik...> (albo --delete jako tryb pracy na plikach usuniętych z repo, wykrytych przez drift_warnings) z tym samym rytmem co write: dry-run domyślny, --dry-run/LIVE jak dziś, DELETE /api/config/<domain>/config/<id> per obiekt, verify (GET → oczekiwane 404) zamiast porównania treści. Scope jak przy write: automations/scripts/scenes.


HA ken: input_number.klima_salon_tolerancja nie ma triggera — zmiana nie przelicza progu

Data: 2026-07-27 Źródło: sesja porządków po audycie (task/ha-porzadki), przy okazji przeglądu 1784804667795 dla konwencji automatyzacji (pkt 17) Problem: "Klima salon: włącz chłodzenie i synchronizuj cel" (1784804667795) ma trigger id: sync na input_number.klima_salon_temp_docelowa (zmiana celu od razu przelicza próg), ale brak odpowiednika dla input_number.klima_salon_tolerancja — to ta sama klasa buga co "trigger brzegowy bez lustrzanego warunku" z audytu (sekcja 3, wzorzec klima_salon z fixu faa2e2a), tylko po stronie triggerów, nie warunków: zmiana tolerancji na dashboardzie nic nie przelicza do najbliższej naturalnej zmiany sensor.thsalon_temperature. Fix: dodać trigger state na input_number.klima_salon_tolerancja do gałęzi sync (albo do analogicznej gałęzi w automatyzacji OFF, jeśli tolerancja wpływa też na próg wyłączenia) w 1784804667795, tak samo jak istniejący trigger na _temp_docelowa.


HA ken: guard TRV kalibracji przed sezonem grzewczym (~2026-09)

Data: 2026-07-23 Źródło: kb/audits/ha-automatyzacje-2026-07-23.md sekcja 1.4 (pkt 2 checklisty operatora) Problem: kalibracje TRV sypialnia (1764751049013) i Tymek (1765817937658) liczą room_temp jako średnią z czujnika zhimi, który jest unavailable od 2026-07-17 → float(0) w formule zaniża temperaturę o połowę → kalibracja dojechała do 5.0 (potwierdzone w fixtures). Latem (TRV off) nieszkodliwe; w sezonie grzewczym = trwałe przegrzewanie obu pokoi. Dodatkowo wszystkie 6 automatyzacji TRV pollują co 4050s (baterie 2038%), a SalonPrawy ma clamp diff ±5 zamiast ±1.5 jak reszta. Fix (przed sezonem): (1) guard is not unavailable na czujnikach zhimi zamiast ślepego uśredniania; (2) ręczny reset kalibracji sypialnia/Tymek po naprawie; (3) zwolnić pętle do ≥5 min lub trigger na zmianę stanu; (4) ujednolicić clamp SalonPrawy; (5) reanimować albo wyłączyć TRV łazienki (number.*_calibration unavailable — urządzenie zniknęło z sieci).


HA ken: przycisk graceful shutdown klimy salonowej na kartę dashboardu

Data: 2026-07-23 Źródło: kb/audits/ha-automatyzacje-2026-07-23.md sekcja 3.1, fix-pack 1 (task/ha-fix-pack-1, DESIGN.md „Decyzje operatora po audycie 2026-07-23") Kontekst: po fix-packu 1 „Klima salon: wyłącz…" (1784804668795) respektuje klima_salon_auto = on dla gałęzi sunset/balkon; suszenie parownika przy ręcznym zgaszeniu klima_salon_auto działa już tylko jako efekt uboczny przełącznika trybu auto (osobna gałąź choose na trigger auto_off). Brakuje wygodnego jednego przycisku „wyłącz klimę i osusz teraz" niezależnego od przełącznika auto. Fix: dodać na dashboard przycisk/skrypt wywołujący script.klima_salon_dry_off bezpośrednio (bez przełączania klima_salon_auto), żeby ręczne graceful shutdown nie wymagało znajomości wewnętrznej logiki automatyzacji.


HA ken: diagnoza wspólnej awarii sprzętowej 2026-07-17 (czujniki ruchu, pilot 4button, xiaomi_miot)

Data: 2026-07-23 Źródło: kb/audits/ha-automatyzacje-2026-07-23.md sekcje 1.2, 1.6, 4.5 (pkt 1, 3, 15 checklisty operatora) Problem: restart HA / update Supervisora 2026-07-17 15:07 zbiega się z unavailable na: klaster czujników ruchu/obecności (mdwejscie, mdsypialnia, mdheli — przynajmniej od restartu; occusalon/mdtymka/mdubikacja gasną w kolejnych dniach — obraz siadających baterii), całej integracji xiaomi_miot (fan.zhimi_mb3/mc2, czujniki temperatury zhimi używane w kalibracjach TRV) i sensor.4button_battery (mimo że pilot 4button strzelał jeszcze 2026-07-12 — 8 automatyzacji salonu na tym urządzeniu). Nie jest jasne, czy to jedna awaria (Zigbee coordinator/integracja) czy zbieg kilku. Fix: (1) sprawdzić fizycznie baterie/re-pairing 6 czujników ruchu + czujnik wycieku WC (pkt 1 checklisty); (2) zdiagnozować integrację xiaomi_miot po stronie HA zamiast łatać pojedyncze automatyzacje (pkt 3); (3) sprawdzić fizycznie baterię pilota 4button (pkt 15). Reanimacja czujników ruchu odblokuje też ~15 cicho martwych automatyzacji (alerty on-leave, nocne gaszenie, Poranek start) — patrz audyt sekcja 1.2 dla pełnej listy skutków.


HA ken: projekt „architektura night_mode" (konsolidacja sleep/night mode)

Data: 2026-07-23 Źródło: kb/audits/ha-automatyzacje-2026-07-23.md sekcje 2.2, 2.4, 6 (pkt 7, 9 checklisty operatora — świadomie NIE załatane w fix-packu 1, patrz DESIGN.md „Decyzje operatora po audycie 2026-07-23") Problem: cztery flagi trybu (sleep_mode, night_mode, passive_mode, movie_mode) o częściowo pokrywającej się semantyce, sprawdzane niespójnie (raz jedna flaga, raz druga, raz OR obu); automation.turn_off_sleep_mode_at_sunrise steruje w rzeczywistości night_mode. Cztery nakładające się automatyzacje gaszą ten sam zestaw świateł nocą (1702844937214 martwa, 1763384250145 martwa, 1768946230585 enforcer co ~10 min całą noc, 1700832676138 o 3:00) — po reanimacji martwych czujników (patrz wpis wyżej) trzy z nich ożyją naraz i zaczną się ścigać. 1768946230585 ma dodatkowo trigger time_pattern /5 obok krawędziowego off→on, więc mimo aliasu „5 minut po aktywacji" gasi światła cyklicznie całą noc — do decyzji, czy to zamierzone. Fix (projekt, nie one-liner): skonsolidować do jednego input_select.tryb_domu + jednej automatyzacji „nocne domknięcie" z jasnym priorytetem trybów i enforcerem (cykliczny dozorca vs. jednorazowe zadziałanie po aktywacji — decyzja pkt 7), plus finalny/ostateczny wyłącznik nocny zastępujący dzisiejsze cztery. Zakres większy niż fix-pack — osobny task.


Executor: zepsuty JSON w approved/ retry'owany w nieskończoność co 10s zamiast trafić do failed//rejected/

Data: 2026-07-23 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: podczas testów E2E remediacji bez SSH zepsuty JSON akcji w approved/ (przyczyna: podstawienie zmiennej lokalnej w cudzysłowie w zagnieżdżonym heredoc przez ssh) powodował, że executor próbował go sparsować co cykl (10s), logując "Failed to move ... to running: Expecting value" bez końca — plik nigdy nie trafiał do failed//rejected/. Fix: executor powinien przenosić nieparsowalny JSON do failed/ (albo dedykowanego malformed/) po pierwszej próbie, nie zostawiać go do nieskończonego retry w approved/.


Uprawnienia actions/ naprawione TYLKO na PIHA (ręcznie) — SOLARIA i lustro niezweryfikowane

Data: 2026-07-23 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: fix uprawnień /opt/homelab/actions (grupa pi + setgid, patrz Zamknięte) zastosowany ręcznie tylko na PIHA. SOLARIA (oskar tam podobno uid 1000 — do sprawdzenia czy problem w ogóle występuje) i lustro (repo-less, patrz osobny wpis niżej) niezweryfikowane — remediacja na tych węzłach może paść identycznie przy pierwszej próbie. Fix docelowy: node-agent powinien sam tworzyć dispatch/<node>/ z właściwymi prawami (grupa współdzielona + setgid) przy starcie, żeby to nie wracało za każdym razem jako ręczna interwencja — patrz też „Tech-debt: globalny porządek uid/gid" niżej.


deploy-local.sh (control-plane): brak twardego checka, że .env istnieje i TAILSCALE_BIND_IP jest ustawione

Data: 2026-07-22 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: przy fixie bindu operator_ui.py:18180 odkryto footgun: bez .env, docker compose tylko OSTRZEGA i po cichu wraca do bindu 0.0.0.0 zamiast failować — dokładnie ten sam wzorzec błędu jak historyczny bug fleet-prometheus/deploy-node.sh (brak --env-file, patrz Zamknięte, commit 686aca7), tym razem w deploy-local.sh/control-plane. Fix: dodać twardy check w deploy-local.sh.env musi istnieć i TAILSCALE_BIND_IP musi być ustawiony, inaczej abort przed docker compose up.


operator_ui.py nie ma ŻADNEJ autoryzacji

Data: 2026-07-22 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: po zamknięciu publicznego bindu 18180 (patrz Zamknięte, commit 9a5c160) operator_ui.py nadal przyjmuje /action/mutate (w tym przejście do approved) bez żadnego uwierzytelnienia — chroni tylko granica Tailscale mesh, nie autoryzacja per operator. Fix: osobny temat — do zaprojektowania (token/basic auth/mTLS w mesh), poza zakresem fixu bindu.


alert_only zapycha approval queue

Data: 2026-07-22 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: przy reconie stanu wyjściowego 16 z 18 pending actions to były liveness-transitions typu alert_only, nie realne decyzje do klikania — operator musi przewijać szum, żeby znaleźć akcje, które faktycznie wymagają Approve/Reject. Fix: rozważyć osobny widok/filtr dla alert_only w operator UI, albo auto-acknowledge bez wejścia do tej samej kolejki co container_restart/redeploy.


Crash-loop nie generuje container_restart — gap detekcja→akcja

Data: 2026-07-22 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: node_exporter na PIHA miał 1048 restartów i event [high], ale supervisor nie wygenerował żadnej akcji container_restart — crash-loop widoczny w evencie nie przekłada się na akcję remediacyjną. Fix: zbadać routing supervisora dla crash-loop sygnałów (disk_pressure i containers_not_running mają jasne mapowanie na akcje w CLAUDE.md — crash-loop najwyraźniej nie).


Telegram yes/no dla pending actions brakuje

Data: 2026-07-22 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: brain-watchdog ma send_telegram (używane dla alertów Prometheus), ale nic nie łączy go z actions/pending — operator musi wejść do operator UI, żeby zatwierdzić/odrzucić akcję, zamiast dostać yes/no bezpośrednio na Telegramie. Fix: rozszerzyć brain-watchdog (albo osobny konsument) o powiadomienie z przyciskami approve/reject per pending action.


homeassistant5 na PIHA: Exited (0), nie podnosi się mimo restart: unless-stopped

Data: 2026-07-22 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: kontener homeassistant5 (legacy HA "ken", patrz cutover kb/phases/backlog.md sekcja "Cutover HA ken") zaobserwowany w stanie Exited (0) — exit code 0 = czyste zatrzymanie, więc Docker restart: unless-stopped świadomie go nie podnosi (to nie crash). Do zweryfikowania, czy to zamierzone wygaszenie z cutoveru czy coś zatrzymało kontener niezamierzenie. Fix: sprawdzić czy to spójne z planem wygaszenia homeassistant5 (patrz cutover HA ken, krok 2 „Wygaszenie homeassistant5") — jeśli tak, brak akcji; jeśli nie, zbadać czemu wyszedł z kodem 0.


lustro: node_agent.py wymaga ręcznego wypchnięcia do /opt/homelab/deploy/node-agent (repo-less)

Data: 2026-07-22 Źródło: sesja 2026-07-22/23 (docs/sessions/2026-07-23-control-plane-remediation-e2e.md) Problem: węzeł lustro nie ma repo/gita — node_agent.py (z fixami remediacji bez SSH, commit 2dac154) musi być ręcznie skopiowany do /opt/homelab/deploy/node-agent, żeby dotrzeć na ten węzeł. Ryzyko rozjazdu repo↔runtime identyczne jak przy innych repo-less węzłach. Fix: ustalić mechanizm dystrybucji kodu node-agenta na węzły repo-less (rsync przy deployu / paczka artefaktu / inny kanał) zamiast ręcznego kopiowania.


🔴 npm@VPS panel admina :81 publicznie osiągalny z internetu

Data: 2026-07-10 Źródło: sesja scripts/npm/npm_api.py (skrypt do zarządzania NPM przez REST API) Problem: services/npm/docker-compose.yml mapuje 81:81 bez ograniczenia do interfejsu — Docker bindem domyślnym wystawia to na 0.0.0.0, czyli panel admina NPM@VPS jest osiągalny z publicznego IP (135.181.153.108:81), nie tylko przez Tailscale mesh (100.95.58.48:81). Panel admina (login+hasło, bez 2FA wymuszonego) nie powinien być publiczny. Brak hosts/vps/runtime/npm/docker-compose.override.yml ograniczającego bind. Fix: dodać override z bindem 127.0.0.1:81:81 (dostęp tylko przez Tailscale/SSH tunnel) albo <tailscale_ip>:81:81, zachowując 80/443 publiczne (to jest ich rola). Zweryfikować po zmianie, że npm_api.py --npm vps nadal łączy się przez 100.95.58.48:81.


Ghosty B WRÓCIŁY — hash-prefixed control-plane na VPS nieposprzątane

Data: 2026-07-06 Źródło: sesja 2026-07-06 (docs/sessions/2026-07-06.md) — snapshot panelu agents.okit.pl Problem: hash-prefixed kontenery control-plane znów widoczne na VPS — wpis „ZNIKNĘŁY (potwierdzone reconem 2026-07-02)" w Zamkniętych zdezaktualizowany. Fix: ręczny docker rm hash-prefixed kontenerów control-plane na VPS; przy okazji sprawdzić, skąd wróciły (fix A 3b71707 miał blokować źródło divergence). Update 2026-07-16 (sesja docs/sessions/2026-07-16.md): po odetkaniu supervisora (event flood + pętla zamrożona, oba naprawione dziś) potwierdzone, że wpisy error w topologii panelu to dokładnie te ghosty — hash-prefixed w world_state observera, NIE żywe kontenery (docker ps -a exited=0 na VPS). Observer nie prune'uje wpisów po zniknięciu kontenerów spod tych nazw. To trzyma System Status: ERROR fałszywie. Fix (do zrobienia): observer powinien weryfikować faktyczny stan kontenera przy budowaniu world_state i prune'ować wpisy dla kontenerów, których już nie ma (ta sama klasa błędu co „Rozjazd world-state observera: NOMINAL przed istnieniem" niżej).


shadow_mode → remediacja: decyzja o auto-restart

Data: 2026-07-16 Źródło: sesja 2026-07-16 (docs/sessions/2026-07-16.md) — wątek control-plane Problem: po odetkaniu supervisora (event flood + pętla zamrożona, oba naprawione dziś) kolejka akcji nadal pusta częściowo dlatego, że shadow_mode=True downgrade'uje HA container_restart do alert_only — supervisor widzi problem, ale świadomie nie enqueue'uje akcji restartu. Do decyzji: czy i kiedy włączyć auto-restart padłych kontenerów — wymaga architektury (guardraile, cooldowny, blast radius per serwis) zanim shadow_mode=false. Patrz też istniejący wpis „ha-diag-agent deploy ZABLOKOWANY" niżej — przed shadow_mode=false tam wymieniony konkretny target (homeassistant5).


gokapi: deploy-node VPS rzuca błąd — brakujący .env

Data: 2026-07-16 Źródło: sesja 2026-07-16 (docs/sessions/2026-07-16.md) — wątek control-plane Problem: deploy-node.sh na VPS rzuca błąd na serwisie gokapi z powodu brakującego .env (/opt/homelab/config/gokapi/.env nieutworzony lub niepełny — wzorzec z sesji 2026-07-09 docs/sessions/2026-07-09-kb-configi-gokapi.md). Fix: sprawdzić services/gokapi/env.example, utworzyć/uzupełnić .env na VPS wg konwencji env.example/opt/homelab/config/<service>/.env.


elasticsearch + diskover w stanie error na PIHA — observer zna usunięte serwisy

Data: 2026-07-06 Źródło: sesja 2026-07-06 (docs/sessions/2026-07-06.md) — snapshot panelu agents.okit.pl Problem: elasticsearch i diskover usunięte z PIHA w module 0 (2026-07-02), ale observer wciąż je zna i raportuje error w panelu. World-state nie zapomina serwisów, które przestały istnieć — ta sama klasa błędu co „NOMINAL przed istnieniem" (patrz wpis z 2026-06-25). Fix: wyczyścić martwe wpisy z world_state / dodać wygaszanie serwisów nieobecnych w desired state i w dockerze.


Gotchas (z 2026-06-30 — migracja kapala.org → Cloudflare/wildcard)

Data: 2026-06-30 Źródło: sesja 2026-06-30 (docs/sessions/2026-06-30-kapala-cloudflare-wildcard-mesh.md)

  • NPM custom WS config + Websockets Support: NIE wklejać proxy_http_version 1.1; do Advanced gdy Websockets Support = ON. NPM dodaje tę dyrektywę sam → duplikat → nginx -t failuje → plik proxy_host/.conf się NIE generuje → "unrecognized name" mimo dobrego certu. Objaw mylący (wygląda jak problem certu/DNS). Diagnoza: strings /data/database.sqlite | grep <domena> → pole nginx_err.

  • Cloudflare auto-proxy na import: CF proxuje A/CNAME przy dodaniu strefy. DKIM CNAME (fm1/2/3._domainkey) proxied = zepsuty podpis maila. Zawsze przełączyć na DNS only (szara chmurka) przed aktywacją. Reserved/CGNAT IP (Tailscale 100.x) CF wymusza DNS only automatycznie.


Migracja okit.pl → Cloudflare (większy projekt, firmowa domena)

Data: 2026-06-30 Źródło: sesja 2026-06-30 (docs/sessions/2026-06-30-kapala-cloudflare-wildcard-mesh.md) Naprawi wszystkie wygasłe certy okit.pl naraz (HTTP-01 failuje przy mesh DNS): ap, audiobooks, code-server, dysk, forgejo, ha-embed, hagc, ngpm, node-red, okit.pl, pihole, ha.okit.pl. Wzorzec jak kapala.org: NS na CF, wildcard *.okit.pl przez DNS-01, przepiąć hosty. UWAGA: okit.pl ma usługi publiczne (foty) — rozdzielić mesh-only od publicznych. Ostrożnie — firmowa domena.


foty.kapala.org renew failuje (#47, expired 2026-06-19, HTTP-01)

Data: 2026-06-30 Źródło: sesja 2026-06-30 (docs/sessions/2026-06-30-kapala-cloudflare-wildcard-mesh.md) Foty są PUBLICZNE celowo (zewn. dostęp za hasłem NPM) — port 80 powinien być dostępny, więc HTTP-01 powinno działać. Sprawdzić czemu failuje (DNS foty wskazuje na zły IP? port 80 zablokowany?). NIE przenosić na mesh.


Cleanup po błędnej ścieżce HA-Tailscale-addon (z 2026-06-29)

Data: 2026-06-30 Źródło: sesja 2026-06-30 (docs/sessions/2026-06-30-kapala-cloudflare-wildcard-mesh.md)

  • ha-ken: Stop + Uninstall add-on Tailscale
  • Tailscale admin: usunąć node ha-ken (100.98.128.40)
  • 42.pl/okit.pl: usunąć rekord ha-ken → 87.205.110.38 (jeśli jest)

Stary ha.okit.pl (cert wygasł 6/28, teraz "Not Used")

Data: 2026-06-30 Źródło: sesja 2026-06-30 (docs/sessions/2026-06-30-kapala-cloudflare-wildcard-mesh.md) Zostawić lub usunąć proxy host + DNS. Niepilne (martwy, nie szkodzi).


Stopniowa migracja usług domowych okit.pl → kapala.org (mesh-only)

Data: 2026-06-30 Źródło: sesja 2026-06-30 (docs/sessions/2026-06-30-kapala-cloudflare-wildcard-mesh.md) dysk, audiobooks, budget, code-server, home, ha-embed, node-red... wg wzorca migracji usługi na kapala.org (patrz sesja: CF rekord A → 100.108.208.3 DNS only, NPM proxy host z wildcard *.kapala.org, Advanced PUSTE, weryfikacja grep+curl).


deploy-node.sh nie reloaduje config-driven serwisów (cicha rozbieżność deploy↔config)

Data: 2026-06-26 Źródło: sesja 2026-06-26 (docs/sessions/2026-06-26.md) Problem: po zmianie prometheus.yml (bez zmiany obrazu) deploy-node.sh NIE recreate'uje kontenera. Compose widzi "kontener działa, obraz ten sam" → zostawia Running, NIE podmienia configu → Prometheus trzyma stary config w pamięci. Deploy raportuje green, a zmiana configu nie wchodzi w życie. Dziś wymagało ręcznego docker compose ... up -d --force-recreate. Dotyczy KAŻDEGO serwisu config-driven bez zmiany obrazu (nie tylko Prometheus). Fix: po zmianie configu serwisu albo --force-recreate, albo POST /-/reload dla serwisów z lifecycle API (fleet-prometheus ma --web.enable-lifecycle). Rozważyć wykrywanie zmiany plików config w deploy i wymuszanie recreate.


Zbadać: chelsty + chelsty-infra node_exporter DOWN z VPS

Data: 2026-06-26 Źródło: sesja 2026-06-26 (docs/sessions/2026-06-26.md) Problem: przy inwentaryzacji targetów floty do fleet-prometheusa, node_exporter na chelsty i chelsty-infra był nieosiągalny z VPS — pominięte w scrape. To LTE edge (intermittent uplink), więc DOWN może być normą, ale wymaga rozróżnienia: brak node_exportera vs odcięty uplink vs zablokowany port. Fix: ustalić, czy node_exporter w ogóle działa na obu chelsty (compose/proces), czy jest osiągalny po Tailscale z VPS, i czy ma sens go scrape'ować mimo LTE (prawdopodobnie tak — up==0 na LTE = sygnał dla anomaly detection, nie fałszywy alarm).


Supervisor nie enqueue'uje akcji remediacji przy error-state

Data: 2026-06-25 (powtórka sygnału z 2026-06-19) Źródło: sesja 2026-06-25 (docs/sessions/2026-06-25.md) Problem: Action Queue pusta mimo System Status ERROR widocznego w panelu. Supervisor nie generuje container_restart / redeploy dla serwisów w stanie error. Objaw zaobserwowany co najmniej dwukrotnie — wymaga izolowanego dochodzenia. Podejrzane: supervisor może nie reagować na error-state jeśli źródłem są ghost kontenery (błędne project-name), nie realne health-check failures. Fix: zbadać osobno — sprawdzić, czy supervisor otrzymuje właściwe eventy od observera, czy ma własną logikę de-duplifikacji blokującą enqueue. Update 2026-07-02: ghost kontenery (bug B) zniknęły z VPS — jeśli objaw wróci, hipoteza "źródłem są ghosty" jest już nieaktualna. UWAGA: ślepy supervisor na SATURN (brak mountu repo, patrz sesja 2026-07-02) to INNY przypadek — nie mylić z tym bugiem. Update 2026-07-16 (sesja docs/sessions/2026-07-16.md, druga połowa dnia): dwie głębsze przyczyny pustej kolejki znalezione i naprawione (petla supervisora zamrożona ~24h — patrz „Supervisor: pętla zamrożona…" w Zamkniętych; event flood 358k plików paraliżujący reconcile — patrz „Event flood…" w Zamkniętych). Po obu fixach supervisor tika i reconcile się kończy, ALE objaw z tego wpisu (brak redeploy mimo widocznego error — elasticsearch/diskover na piha, ollama solaria) nadal aktualny — drift→action nie domyka się mimo odetkanego mózgu. Zostaje otwarte jako osobne dochodzenie.


Rozjazd world-state observera: panel pokazuje serwis NOMINAL przed jego istnieniem

Data: 2026-06-25 Źródło: sesja 2026-06-25 (docs/sessions/2026-06-25.md) Problem: panel wykazał fleet-prometheus jako nominal na SOLARII zanim kontener w ogóle istniał — observer world_state rozjechany z dockerem. Artefakt rejestracji w manifeście bez realnego kontenera. Podobna klasa błędu jak ghost kontenery. Fix: observer powinien weryfikować faktyczny stan kontenera przy budowaniu world_state zamiast opierać się wyłącznie na zarejestrowanych serwisach.


🔴 BLOKUJĄCE — FLOTA-BOMBA: node-agent SSH mount ślepy po recreate

Data: 2026-06-11 Źródło: sesja lustro ssh shipping fix Problem: solaria/piha/chelsty to stare root kontenery node-agenta (piha Created 2026-05-27, uid 0) — sprzed dodania user: "1000:1000" do bazowego compose. Ich override montuje klucz SSH w /root/.ssh, co działa tylko dla uid 0. Pierwszy --force-recreate / reboot hosta / update obrazu przełączy kontener na uid 1000 (homelab, HOME=/home/homelab) i shipping eventów na VPS padnie z "Permission denied" — dokładnie jak na lustrze (naprawione a5a1352). ssh w _ship_events_to_vps() nie ma -i i szuka klucza w $HOME/.ssh. ⚠️ NIE RECREATE node-agenta na solaria/piha/chelsty przed fixem. Fix: ujednolicić mount → /home/homelab/.ssh we wszystkich hosts/*/runtime/node-agent/docker-compose.override.yml (wzór: hosts/lustro/) ALBO dodać -i $HOME/.ssh/id_rsa w _ship_events_to_vps().


ha-diag-agent deploy ZABLOKOWANY (placeholder token)

Data: 2026-06-11 Źródło: sesja — deploy config merged (5e9db5c), .env na piha utworzony (/opt/homelab/config/ha-diag-agent/.env, chmod 600) ale token = PLACEHOLDER. Blokada: chelsty-ha offline → brak tokenu i połączenia. Do decyzji: cel HA — chelsty-ha vs HA Ken (homeassistant5 na piha; z kontenera NIE localhost). Przed shadow_mode=false: target restartu w supervisorze = nazwa kontenera homeassistant5; curl endpointu HA z tokenem = HTTP 200.


observer-poison-quarantine — review brancha (78c9e4a)

Data: 2026-06-11 Źródło: sesja — patch Codexa zachowany na task/observer-poison-quarantine, NIE w master. Do zrobienia: zweryfikować, czy observer realnie wiesza się na malformed evencie (poison NIE był przyczyną awarii lustra — hipoteza niezweryfikowana, obalona przez verify-before-fix). Realny bug → merge; inaczej → drop brancha i worktree.


node_agent.py — drobne sprzątanie shippingu

Data: 2026-06-11 Źródło: sesja lustro ssh shipping fix

  1. Stale komentarz node_agent.py:546-548 — twierdzi, że kontener "runs as root"; nieaktualne od user: "1000:1000".
  2. Sukces shippingu na logger.debug → podnieść do info lub dodać licznik — działający shipping jest niewidoczny w logach przy INFO, co utrudniało diagnozę (cicha awaria wyglądała identycznie jak ciche działanie).

event-bloat: wyczyścić spłynięty backlog lustro na VPS

Data: 2026-06-11 Źródło: sesja — po fixie shippingu 7600+ plików backlogu spłynęło do /opt/homelab/events/lustro/ na VPS. Fix: wyczyścić stare pliki (observer już je przetworzył); docelowo polityka retencji w event-store.


rsync --omit-dir-times (node-agent)

Data: 2026-06-09 Źródło: flota recovery session Objaw: rsync exit code 23 po każdym push — set-times na katalogu /opt/homelab/events/ zwraca EPERM (oskar nie jest właścicielem katalogu; aerbot jest). Pliki są kopiowane poprawnie, ale exit 23 zaśmieca logi i może maskować prawdziwe błędy. Fix: dodać --omit-dir-times do wywołania rsync w node-agent.py. Lokalizacja: services/node-agent/src/node_agent.py — wywołanie rsync w pętli push. Update 2026-06-11: potwierdzone flotowo — każdy node loguje fałszywe "Event shipping failed" (rsync code 23) co cykl, mimo że pliki przechodzą; katalogi /opt/homelab/events/* na VPS należą do aerbot, klient nie ustawi na nich czasów.


Deklaratywny zapis oskar ∈ aerbot w manifeście VPS

Data: 2026-06-09 Źródło: flota recovery — root cause: oskar spoza grupy aerbot(1000) → rsync Permission denied Problem: przynależność do grupy jest zarządzana ręcznie (usermod -aG 1000 oskar ad-hoc). Brak gwarancji po przeinstalowaniu VPS lub zmianie usera. Fix: dodać do hosts/vps/host.yaml lub hosts/vps/capabilities.yaml sekcję users: oskar: groups: [aerbot] — i wyegzekwować w deploy/bootstrap skrypcie VPS. Alternatywa: zmienić właściciela /opt/homelab/events/ na oskar:oskar i zaktualizować node-agent deploy skrypty.


Rozdzielenie worktree per task (agent.sh)

Data: 2026-06-09 Źródło: sesja — homelab-codex-ws-node-onboarding używany raz dla task/node-onboarding, raz dla task/fix-event-bloat przez ręczne git checkout. Problem: jeden worktree współdzielony przez dwa branche = anty-wzorzec. git branch mogło wskazywać zły branch; + w listingu = pozornie "w innym worktree" ale nieprawda. Prowadzi do commitowania na złej gałęzi. Fix: egzekwować — jeden task = jeden worktree (agent.sh new <task-name>). Przy wejściu do worktree zawsze git branch --show-current i weryfikacja .agent-task. Długoterminowo: agent.sh new powinien odmawiać jeśli żądana gałąź jest już sprawdzona.