# Tech-debt backlog Centralny tracker tech-długu i znanych usterek. Wpisy ze sesji — dodawaj z datą i kontekstem. --- ## Plan: Monitoring floty — Prometheus jako źródło prawdy **Data**: 2026-06-22 **Źródło**: sesja 2026-06-22 (`docs/sessions/2026-06-22.md`) **Decyzja**: Prometheus (pull, `up{}`) zastępuje warstwę WYKRYWANIA liveness (node-agent shipper + rsync/ssh + event-store + observer prune/checkpoint + ręczne TTL) — przyczynę nawracających awarii (uid≠1000, ślepy ssh-mount, bloat ~242k eventów, race prune↔checkpoint, NOMINAL-bez-TTL). Osobny fleet-Prometheus pod GitOps, **nie** adopcja domowego instance PIHA. **BEZ** Alertmanagera — alert przez brain-watchdog. Placement: VPS. Granica: zostają supervisor (remediacja), observer/panel, ha-diag-agent, historia incydentów, out-of-band watchdog. > Zastępuje wcześniejszy szkic (blackbox + Alertmanager) z sesji 2026-06-17. **Kroki (priorytetowo)**: 1. Scaffold serwisu `fleet-prometheus` pod GitOps (worktree `task/fleet-prometheus`, wzorzec `services/vikunja/`): compose + `env.example` + `service.yaml` + README + `healthcheck.sh`; rejestracja w `hosts/vps/services.yaml` + `inventory/topology.yaml`; exposure `tailscale-internal`; pusty scrape na start (self + lokalny `node_exporter` VPS). 2. Inwentaryzacja nodów floty `100.x` do scrape (osobny krok). 3. Container-layer exporter (cAdvisor lub lekki docker-state) — `node_exporter` nie widzi kontenerów. 4. Reguły liveness (`up==0 for: 5m`) w Prometheusie. 5. brain-watchdog: drugie wejście — odpyt Prometheus `/api/v1/alerts` (`firing`) → Telegram, bez ruszania działającego toru `token → chat_id`. 6. Rotacja tokenu HAOS w domowym prom (plaintext). 7. Przepięcie observer / panel `agents.okit.pl` na Prometheus jako źródło — największy znak zapytania przy cutoverze. 8. Parallel-run obok rury eventowej; cutover dopiero gdy Prometheus-truth się udowodni. --- ## Aktywne ### Rozjazd stanu Docker Compose na VPS — serwisy poza GitOps project-name **Data**: 2026-06-24 **Źródło**: sesja 2026-06-24 (`docs/sessions/2026-06-24.md`) **Problem**: `node-agent`, `control-plane` i inne serwisy VPS zostały utworzone inną ścieżką / `project-name` niż widzi `deploy-node.sh` (bo VPS nigdy nie deployował się tą ścieżką przed hostname-fixem z `ae739b5`). Przy próbie Recreate pada: `Error: No such container: _node-agent`. `set -e` przerywa całą pętlę. **⚠️ Dotyka żywego control-plane (~7 dni uptime) — ostrożnie, osobna sesja.** **Fix**: uspójnić `project-name` — recreate z czystymi labelami Compose albo migracja do jednego `--project-name` dla całego `deploy-node.sh`. --- ### Flaky testy control-plane — state-leak w pytest (gate nierzetelny) **Data**: 2026-06-24 **Źródło**: sesja 2026-06-24 (`docs/sessions/2026-06-24.md`) **Problem**: `test_incident_lifecycle.py::test_run_once_quarantines_bad_event` i `::test_run_once_skips_observer_emitted_events` failują przez state-leak między przebiegami pytest. Moduł-level stałe `EVENTS_DIR` / `FAILED_EVENTS_DIR` / checkpoint wskazują poza `tmp_path` testu — asercje porównują ścieżki z różnych `pytest-N` runs. Kod observera zdrowy (quarantine i checkpoint działają poprawnie). Gate deploy.sh czerwony przy zdrowym kodzie → zmuszeni do `--no-gate`. **Fix**: zmockować ścieżki na `tmp_path` przez fixture w testach observera. **Skutek bieżący**: gate nierzetelny — każde `--no-gate` musi być odnotowane. --- ### 🔴 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 `). 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. --- ## Zamknięte ### Swap 2–4 GB na VPS — ZROBIONE **Data**: 2026-06-22 (zgłoszone PENDING w sesji 2026-06-09 flota-recovery) **Źródło**: sesja 2026-06-22 (`docs/sessions/2026-06-22.md`) **Było**: VPS (3.7 GB RAM) z `swap=0` → OOM 2026-06-01. **Zrobione**: `/swapfile` 4 GB aktywny i trwały (wpis w `/etc/fstab`); `vm.swappiness=10` na żywo i w `/etc/sysctl.conf`. Weryfikacja: `free -h` → `Swap: 4.0Gi (0B used)`, `/proc/swaps` zawiera `/swapfile`. **Uwaga**: host-level one-off (nie czysto GitOps), udokumentowany jako celowy host-state w `hosts/vps/host.yaml`. Brak commitu kodu — zmiana host-side gotowcem. --- ### Observer staleness — martwy node pokazywany NOMINAL **Data**: 2026-06-08 (złapane), status: OTWARTY w sensie implementacji **Problem**: observer/supervisor trzyma ostatni znany stan; brak heartbeat TTL. Chelsty-infra milczy, ale status NOMINAL podważa zaufanie do panelu. **Fix**: heartbeat TTL → po przekroczeniu oznacz status `stale` lub `down`. **Powiązane**: brain-watchdog ślepy na per-node freshness. *(Otwarty jako TODO implementacyjny — przeniesiony z sesji 2026-06-08)*