homelab-codex-ws/docs/sessions/2026-08-26.md

188 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Session 16:00
Recon floty po 3 tygodniach bez nadzoru (ostatnia sesja 2026-08-06) + sesja
naprawcza: (A) usunięcie watchtowera z LUSTRO jako reliktu spoza GitOps,
(B) higiena kolejek `actions/pending` i zawieszonych incydentów `active` na VPS.
SUPERVISED — checkpointy A/B/C zatwierdzane przez operatora, backup przed
każdą operacją destrukcyjną.
### Commits
Ta sesja nie wprowadziła żadnych commitów w kodzie poza niniejszym logiem —
wyłącznie operacje na nodach (LUSTRO, VPS). Jeden niepowiązany commit
(`003f83d`, kb-publish skill) doszedł na `master` od równoległej sesji
operatora w międzyczasie — poza zakresem tej sesji.
```
(brak commitów tej sesji)
```
### Files changed
Brak zmian w repo.
### Deploys / operacje na nodach
**Recon (read-only, wszystkie 4 węzły: SOLARIA, PIHA, VPS, LUSTRO):**
- Zero nowych commitów na `origin/master` przez 3 tygodnie.
- Soak test R1 (auto-cleanup node-agenta): PIHA 20/20 uruchomień 0 usunięć,
VPS 21/21 uruchomień 0 usunięć, SOLARIA 3/3 0 usunięć, LUSTRO 5/5 —
1 usunięcie (`prune-disposable`, celowy kanarek testowy z 08-06, zgodnie
z zamysłem). Zero ofiar wśród kontenerów chronionych. `rc=23` nie wystąpił
ani razu — fix `0o775` z sesji 08-06 trzyma.
- Zdiagnozowano ciągłą pętlę restartów `pi-watchtower-1` na LUSTRO (API
Docker 1.25 vs wymagane min. 1.40), trwającą nieprzerwanie od co najmniej
2026-08-06 04:31.
**Watchtower LUSTRO — usunięcie (checkpoint A→B, zatwierdzony):**
- Backup: `docker inspect` + `compose.yml` + pusty katalog `/home/pi/watchtower`
`/home/pi/watchtower-removal-backup-2026-08-26/` na LUSTRO.
- `docker stop` + `docker rm pi-watchtower-1`, `docker rmi containrrr/watchtower:latest`,
`/home/pi/compose.yml` (jedyne źródło autostartu — brak systemd/cron) przeniesiony
do backupu jako `.disabled`.
- Weryfikacja: `docker ps -a` na LUSTRO czyste; 7 min ciszy zdarzeń
`containers_not_running-watchtower` na VPS (wymagane min. 5 min).
**Higiena kolejek VPS (checkpoint C→wykonanie, zatwierdzony):**
- Backup: `tar czf /opt/homelab/backups/actions-incidents-2026-08-26.tgz`
(`actions/` + `world/incidents.json`), sha256 `ef9afbfa...`.
- 17/18 pending → `cancelled/` (`stale_manual_cleanup`): 16× stare
`alert-node-*`/`alert-ha-*` z czerwca + 1× shadow-mode HA-websocket z 13.08
(kolizja nazwy pliku z niepowiązanym wpisem z 08-06 — zapisany pod nową
nazwą `container-restart-piha-homeassistant-shadowmode-20260813.json`,
żeby nie nadpisać cudzej historii).
- `redeploy-vps-gokapi` **pozostawiony** — realna luka wdrożeniowa (desired
w `hosts/vps/services.yaml`, brak kontenera), nie cruft. Follow-up do
sesji deploy.
- 5 incydentów w `world/incidents.json` ręcznie przełączonych na `resolved`
(`piha-homeassistant`, `solaria-narty27`, `solaria-prune-canary`,
`lustro-prune-canary`, `lustro-watchtower`) — wszystkie zdiagnozowane jako
trwale osierocone (brak mechanizmu auto-resolve dla zniknionej/przeniesionej
usługi, patrz Narrative).
- Sekwencja bez wyścigu: `docker stop control-plane-observer` → edycja pliku
`docker start` → weryfikacja >15 s (kilka cykli flush) — bo `_save_world()`
nadpisuje `world/*.json` co 5 s z pamięci procesu, bez merge z dyskiem.
- Efekt uboczny własnego restartu: `inc-...-vps-observer` (1 wystąpienie) —
rozwiązał się sam w ~60 s (poprawny, nieosierocony przypadek).
- Stan końcowy: `active_incidents_count: 0`, `runtime-summary.json status: nominal`.
### Narrative
> _user-provided summary_
## Session 23:00
Deploy control-plane (observer + supervisor) na VPS: stale-resolve 24h +
flagi `resolve-requests` (commit `71a7af5`), unikalny `action_id`
`container_restart` z bare-id fallbackiem (commit `91db682`), usunięcie
gokapi z desired state (commit `74ff3ee`) — zmerdowane do `master` jako
`f155999` przez operatora tuż przed sesją. SUPERVISED — checkpoint A po
weryfikacji deployu, checkpoint B po teście ścieżki flagi.
### Commits
```
(brak commitów kodu tej sesji — wyłącznie deploy + test na produkcji;
log sesji poniżej dopisany bez pusha)
```
### Files changed
Brak zmian w repo poza niniejszym logiem.
### Deploys / operacje na nodach
**KROK 0 — sanity:** `git pull` na `~/homelab-codex-ws` (SOLARIA, główny
checkout) — już aktualny na `03441a1` (na wierzchu mergu `f155999`).
`git status`/`diff HEAD` czyste. Wcześniej w tej samej sesji (przed
mergem) `git log -1` pokazywał `4fa10f0` — merge jeszcze nie istniał;
zatrzymano się i poczekano na operatora zamiast mergować samodzielnie
(worktree-aware: merge to wyłącznie krok człowieka).
**KROK 1 — deploy control-plane (checkpoint A, zatwierdzony):**
- Rollback tagi: `control-plane-{executor,observer,operator-ui,supervisor}
:rollback-pre-resolvefix` — ten sam wzorzec co `:rollback-pre-dispatchfix`
z 08-06.
- `git pull origin master` na VPS (`003f83d` → `03441a1`, fast-forward),
`docker compose up -d --build --force-recreate`.
- `deploy-local.sh`'s auto-chown krok padł: brak TTY dla hasła sudo,
`/opt/homelab/backups` i `/opt/homelab/events/solaria/*``oskar:oskar`
zamiast `aerbot:aerbot` (1000). Sprawdzone: `actions/`, `world/`,
`state/`, `config/` (realna ścieżka zapisu control-plane) już poprawnie
`aerbot:aerbot 775` — ominięto self-heal, `docker compose` odpalony
bezpośrednio bez sudo. Mismatch na `backups/`/`events/solaria/*`
pozostawiony nietknięty (follow-up niżej).
- Weryfikacja: 4/4 kontenery `healthy`, 0 linii error/traceback/exception
od restartu. sha256 `observer.py` (mount `/repo`, żywy) i `supervisor.py`
(wypieczony `/app/src`, wymaga `--build`) == repo HEAD, potwierdzone
osobno przez `docker exec` w obu kontenerach.
- Po 3 cyklach reconcile: `active_incidents: 0`, `world/resolve-requests/`
utworzony przez observera (pusty).
- `redeploy-vps-gokapi` (pending od 07-09) auto-cancelled po pierwszym
cyklu: `cancelled_reason: "service_removed_from_desired_state"` — bez
ponownego wygenerowania. `pending/` pozostał czysty (tylko niezwiązane
alerty HA z piha).
**KROK 2 — test ścieżki flagi na LUSTRO (checkpoint B, zatwierdzony):**
- `docker stop node-exporter` na LUSTRO → observer otworzył
`inc-1787777894-lustro-node-exporter`.
- Flaga: `touch world/resolve-requests/<id>` przez zwykłego SSH
usera **odrzucony permission denied** — katalog `755 aerbot:aerbot`,
brak zapisu grupowego mimo że `oskar` jest w grupie `aerbot`. Obejście:
`docker exec control-plane-observer touch ...` (proces w kontenerze
działa jako uid 1000 = właściciel katalogu). Follow-up niżej.
- Resolve w **1.01 s** od touch (limit ≤10s), `resolved_reason:
manual_operator`, flaga skasowana, `service.incident_id` wyczyszczony,
log INFO `"Manually resolving incident ... via resolve-request flag"`.
- Drift trwał dalej (kontener wciąż stopped) → supervisor wygenerował
`container-restart-lustro-node-exporter-1787777887` — **nowy format
id z COMMIT 2 potwierdzony na produkcji** — oraz równolegle
`redeploy-lustro-node-exporter` (bare id, ścieżka `unhealthy_service`
po wyczyszczeniu `incident_id`).
- Za decyzją operatora: `POST /action/mutate` na `127.0.0.1:18180`
(ten sam endpoint co UI/Telegram) — zatwierdzono restart, odrzucono
redeploy jako nadmiarowy.
- Executor zdispatchował realnie do LUSTRO; node-agent wykonał
`docker restart node-exporter` (log: `"Restarted container
'node-exporter' for action container-restart-lustro-node-exporter
-1787777887"`), akcja `completed`.
- Drift utrzymał się jeszcze chwilę po zatwierdzeniu → drugi, nowy
incydent (`inc-1787777955-...`) i druga, odrębna pending akcja
(`...-1787777950`, inny suffix `started_at`) — dokładnie oczekiwane
zachowanie "różny id przy nowym incydencie". Po powrocie zdrowia
auto-cancelled: `cancelled_reason: "drift_resolved_auto"`, bez
interwencji.
- Stan końcowy: `node-exporter` na LUSTRO `Up`, oba incydenty
`resolved`, `active_incidents: 0`, `pending/` czysty, 4/4 kontenery
control-plane nadal `healthy`, 0 error-ish linii w logach.
### Follow-upy
- **pytest env zepsuty na SOLARII**: `~/.local/bin/pytest` (brak
`_pytest`) i `homelab-codex-ws/.venv` (brak `pytest` w ogóle) oba
niedziałające; działa wyłącznie `/home/oskar/anaconda3/bin/pytest`
(7.4.4). Użyty do pełnego runu przed force-pushem poprawki COMMIT 2
(184 passed control-plane, 70 passed node-agent).
- **`world/resolve-requests/` permissions**: `755 aerbot:aerbot` zamiast
konwencji `775` używanej w `actions/`/`world/`/`state/`/`config/`.
Blokuje operatora SSH przed bezpośrednim `touch` flagi resolve —
manualna ścieżka z 71a7af5 ("operator drops a file") w praktyni wymaga
`docker exec`. Poprawić `chmod 775` / mode przy `os.makedirs` w
observer.py.
- **`backups/` i `events/solaria/*` ownership**: `oskar:oskar` zamiast
`aerbot:aerbot` — nie blokuje funkcjonalnie (czytelne dla "other"), ale
psuje self-heal chown w `deploy-local.sh` (próbuje rekurencyjnego sudo
chown całego `/opt/homelab` bez TTY/hasła). Do ręcznego wyczyszczenia
z hasłem sudo albo do zmiany self-heal na scoped (tylko katalogi
control-plane realnie potrzebuje) zamiast całego drzewa.
- **CLAUDE.md doc drift**: opisuje `events/YYYY-MM-DD/<node>/events.jsonl`,
rzeczywisty layout na VPS to płaskie `events/<node>/evt-*.json` (jeden
plik na zdarzenie, bez partycjonowania po dacie). Do poprawienia przy
najbliższej okazji.
- `redeploy-vps-gokapi` — zamknięty tym deployem (auto-cancelled), nie
wymaga już dalszego follow-upu z sesji 16:00.
### Narrative
> _user-provided summary_