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>
32 KiB
| okf | type | visibility | status | updated | links | |
|---|---|---|---|---|---|---|
| 0.1 | decision | private | active | 2026-08-03 |
|
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 private — services/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
40–50s (baterie 20–38%), 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
- Stale komentarz
node_agent.py:546-548— twierdzi, że kontener "runs as root"; nieaktualne oduser: "1000:1000". - Sukces shippingu na
logger.debug→ podnieść doinfolub 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.