Wdrozenie do runtime dwoch zmergowanych commitow (52eca1c,1bab321), zero zmian w kodzie. Deploy przez deploy-service.sh --build-if-needed, nie przez deploy.sh <target>: ten drugi to dyspozytor Saturn-side po SSH deployujacy caly node (na VPS ruszylby npm/outline/joplin/ai-cluster), a sesja toczyla sie z SOLARII, gdzie `ssh solaria` to polaczenie do samego siebie. Pierwszy cykl prune po zdjeciu M1 poszedl zgodnie z ostrzezeniem z1bab321— markera last-docker-cleanup nie bylo na zadnym z nodow, wiec cleanup odpalil ~0,5 s po starcie. Zero ubytkow kontenerow (SOLARIA 9/9, VPS 24/24), humanai-* nietkniete. Dwie prognozy wymagaly korekty, obie bo `docker images` pokazuje rozmiar pozorny z warstwami wspoldzielonymi: na SOLARII 4 dangling zniknely, ale SpaceReclaimed=0 (warstwy dzielone z control-plane i kb-query), a na VPS jedyny dangling okazal sie zywym obrazem outline-postgres-1 (flaga U) i prune go nie ruszyl — slusznie. Test dispatch end-to-end: wszystkie 6 kryteriow spelnione. dispatch/lustro 755 -> 775 w momencie zapisu przez executora, plik akcji zniknal ze zrodla i nie wrocil, oba zalegle pliki z 10:39 i 11:08 zdrenowaly sie przy okazji, a spam "already processed — skipping" co 60 s ustal. Poszlo przez approved/, nie przez approval operatora: supervisor auto-anulowal pending po 7 s jako drift_resolved_auto, zanim operator zdazyl kliknac. Klasyfikacja rc=23 pozostaje niezweryfikowana na zywo — LUSTRO ma nadal stary node-agent (fee079e8), ktory fizycznie nie umie tego zalogowac (follow-up #3). Refs docs/sessions/2026-08-06.md (follow-up #1, #5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
11 KiB
| okf | type | visibility | status | updated | links |
|---|---|---|---|---|---|
| 0.1 | session-log | private | active | 2026-08-06 |
Session log 2026-08-07
Uwaga do datowania. Praca wykonana 2026-08-06, 14:10–15:25 CEST. Plik nosi datę następnego dnia na wyraźne życzenie operatora, bo
docs/sessions/2026-08-06.mdjest już zajęty przez sesję fazy mailowej z tego samego okna. Wszystkie znaczniki czasu w treści są rzeczywiste (2026-08-06).
Session 15:25
Wdrożenie do runtime dwóch fixów zmergowanych na master (supervised, checkpointy
zatwierdzane przez operatora): dispatch 0o775 + rc=23 w executorze/node-agencie
(52eca1c) oraz zdjęcie mitygacji M1 na SOLARII i VPS (1bab321).
Commits
Ta sesja nie wprowadziła żadnych commitów poza niniejszym logiem — deploy runtime,
zero zmian w kodzie. Wdrożone commity powstały wcześniej, na branchu
task/dispatch-perms-m1:
1bab321 revert(m1): zdjecie NODE_TYPE=lte_node na SOLARII i VPS po wdrozeniu R1
52eca1c fix(dispatch): inbox 0o775 + rsync rc=23 przestaje byc cichy
W trakcie sesji main checkout przesunął się o 75d9695 docs(recon): przyrostowka IMAP gmail + fastmail (druga sesja operatora, docs-only). Bez wpływu: node_agent.py ma to
samo sha256 aec6cb03 w obu drzewach, więc SOLARIA — zdeployowana jeszcze z 1bab321 —
nie rozjechała się z VPS-em deployowanym z 75d9695.
Files changed
Brak — drzewo robocze czyste przez całą sesję, poza tym plikiem.
Deploys
| Node | Serwis | Przed | Po | Wynik |
|---|---|---|---|---|
| SOLARIA | node-agent | node_agent.py fee079e8, obraz 438111e2 |
aec6cb03 == repo HEAD, obraz bc28a30a |
OK |
| VPS | node-agent | node_agent.py c21967d3, obraz 27be875d |
aec6cb03 == repo HEAD |
OK |
| VPS | control-plane | executor.py 5ca0490e, 4 obrazy z 2026-08-05 |
1c3b569f == repo HEAD, 4 obrazy przebudowane |
OK |
Mechanizm: scripts/deploy/deploy-service.sh --build-if-needed dla node-agenta (ta sama
ścieżka co 2026-08-05). Nie użyto scripts/deploy/deploy.sh <target>: jest to
dyspozytor Saturn-side po SSH, deployujący cały node — na VPS ruszyłby npm, outline,
joplin i ai-cluster, czyli daleko poza zakres, a sesja toczyła się z SOLARII (ssh solaria
to połączenie do samego siebie).
NODE_TYPE po zdjęciu M1: SOLARIA lte_node → ai_node (jawnie w override),
VPS lte_node → linia usunięta, NODE_TYPE="" z base compose → _resolve_node_type()
zwraca standard. Log startowy potwierdza jedno i drugie (type=ai_node, type=standard),
czyli przewidywanie z commita 1bab321 co do pustego stringa było trafne.
Gate testowy: pytest niedostępny w main checkoucie (.venv bez pytest,
~/.local/bin/pytest ma zepsuty _pytest). Oparto się na wyniku sprzed merge'a
(node-agent 70 passed, control-plane 173 passed) plus docker build obu stacków przy
deployu. Follow-up #4.
Pierwszy cykl cleanup po zdjęciu M1
Na obu nodach marker /opt/homelab/state/last-docker-cleanup nie istniał (M1 blokował
zapis od 2026-08-04), więc _cleanup_rate_ok() zwrócił True i prune poszedł w pierwszym
cyklu, ~0,5 s po starcie — zgodnie z ostrzeżeniem w 1bab321. Dlatego kolejność w każdym
kroku była: najpierw tagi rollback, potem deploy.
SOLARIA:
INFO - node-agent starting: node=solaria type=ai_node
INFO - Pruned dangling images (0 MB reclaimed)
INFO - No disposable stopped containers (kept 0 managed)
INFO - Pruned build cache (91 MB reclaimed)
VPS:
INFO - node-agent starting: node=vps type=standard
INFO - Pruned dangling images (0 MB reclaimed)
INFO - No disposable stopped containers (kept 0 managed)
INFO - Pruned build cache (239 MB reclaimed)
Zero ubytków kontenerów na obu nodach — docker ps -a przed vs po, diff nazw pusty
(SOLARIA 9/9, VPS 24/24). humanai-mailer i humanai-landing (bez definicji w repo)
nietknięte. Tagi rollback-* przeżyły prune.
Dwie prognozy przedwdrożeniowe wymagały korekty — obie z tego samego powodu, że
docker images pokazuje rozmiar pozorny z warstwami współdzielonymi, a nie realny
odzysk:
- SOLARIA, „4 dangling ≈ 553 MB": cztery obrazy faktycznie zniknęły (35 → 32, przy
+1 nowym buildzie), ale
SpaceReclaimed= 0 MB. Ich warstwy są współdzielone z control-plane i kb-query. Realny odzysk obrazów ≈ 70 MB (17,89 → 17,82 GB); z build cache (606,1 → 510,5 MB) łącznie ≈ 165 MB. - VPS, „1 dangling 395 MB": ten obraz to żywy
outline-postgres-1— untagged, ale oznaczonyU(in use). Docker odmawia usunięcia obrazu używanego przez kontener, więc prune go nie ruszył i nie miał prawa ruszyć. Realny odzysk to wyłącznie build cache 239 MB (z 250,8 MB reclaimable).
Kontener control-plane-ui na SOLARII stoi w stanie created — poza zasięgiem prune'a
podwójnie: _prune_stopped_containers() listuje wyłącznie status=exited, a kontener ma
i tak label compose oraz restart=unless-stopped.
Weryfikacja fixu dispatch end-to-end
Stan wejściowy zdjęty przed deployem control-plane (patrz follow-up #1 — inaczej
deploy-local.sh by go zatarł):
| ścieżka | mode | |
|---|---|---|
actions/dispatch/piha |
775 | historycznie działał |
actions/dispatch/lustro |
755 | wyciek |
actions/deploy |
755 | inbox deploy-runnera, bez podkatalogów |
Mechanizm potwierdzony co do joty: inbox aerbot:aerbot 755, a ciągnie z niego
VPS_EVENTS_USER=oskar — uid 1002, tylko członek grupy aerbot (gid 1000). Grupa ma
r-x bez w, więc --remove-source-files nie może zrobić unlinku. Dwa pliki akcji z
10:39 i 11:08 leżały w źródle, a LUSTRO re-pullowało je co 60 s, odbijając od bramki
idempotencji:
13:15:13 INFO - Action container-restart-lustro-node-exporter already processed — skipping
13:15:13 INFO - Action container-restart-lustro-watchtower already processed — skipping
13:16:16 ... (to samo) 13:17:19 ... (to samo)
Test HITL. Cel zmieniony z watchtower na node-exporter: watchtower na LUSTRO jest
w crash-loopie (137 restartów, restart=always, nie potrafi pullnąć lokalnego obrazu
piper-tts-rpi5 — 401 z Docker Huba), więc nie dałby czystego sygnału. Nowe action_id
(container-restart-lustro-node-exporter-dispatchfix), bo recykling starego odbiłby się od
bramki idempotencji na LUSTRO i zawiesiłby akcję w running do timeoutu.
Ścieżka: przez approved/, nie przez approval operatora. Plik pending zapisany
13:16:56 UTC został auto-anulowany przez supervisora po 7 sekundach
(drift_resolved_auto — node-exporter był zdrowy), zanim operator zdążył kliknąć. Zgodnie
z ustaleniem przed testem druga kopia trafiła prosto do approved/; cel testu to mechanika
dispatchu, nie ścieżka approvalu. Pole status w tej kopii zostało cancelled — bez
znaczenia, executor kieruje się katalogiem, nie polem.
Wynik — wszystkie sześć kryteriów spełnione:
- 755 → 775 dokładnie w momencie zapisu przez executora (13:17:23) ✅
- plik akcji zniknął ze źródła po pobraniu i nie wrócił w kolejnych cyklach ✅
- oba zaległe pliki zdrenowane przy okazji —
dispatch/lustro/całkowicie pusty ✅ - spam
already processed — skippingustał: dwa pełne cykle (13:19:25, 13:20:28) z zerem trafień ✅ - akcja
completedprzezaction_resultpo 70 s,node-exporterz nowym uptime ✅ - zero ERROR/WARNING w executorze, observerze, supervisorze i node-agentach — poza znanym, niezwiązanym crash-loopem watchtowera na LUSTRO ✅
13:18:23 INFO - Restarted container 'node-exporter' for action container-restart-lustro-node-exporter-dispatchfix
Czego ten test NIE dowiódł. Druga połowa fixu — klasyfikacja rc=23 z WARNING-iem — na
LUSTRO nie pojechała: node-agent tam ma nadal fee079e8 (ten sam sha, który SOLARIA miała
przed dzisiejszym deployem). grep -c "rc=23" = 0 w logach LUSTRO dlatego, że stary kod
fizycznie nie umie tego zalogować, a nie dlatego, że jest dobrze. Follow-up #3.
Stan tagów rollback
| Node | Tag | Image ID |
|---|---|---|
| SOLARIA | node-agent:rollback-pre-dispatchfix |
438111e2 |
| SOLARIA | node-agent:rollback-pre-r1 (z 2026-08-05) |
c80a711f |
| VPS | node-agent:rollback-pre-dispatchfix |
27be875d |
| VPS | control-plane-executor:rollback-pre-dispatchfix |
b878d835 |
| VPS | control-plane-observer:rollback-pre-dispatchfix |
4b79511d |
| VPS | control-plane-supervisor:rollback-pre-dispatchfix |
357b70d1 |
| VPS | control-plane-operator-ui:rollback-pre-dispatchfix |
e522bbaa |
Pierwsze tagi rollback-* na VPS w ogóle. Otagowano wszystkie cztery obrazy control-plane,
nie tylko executora — deploy-local.sh przebudowuje cały stack, więc każdy potrzebuje celu
rollbacku.
Follow-upy
deploy-local.shrobi rekurencyjnychown+chmodna całym/opt/homelab— do przeglądu, czy to w ogóle pożądane. Oba branche by dziś zadziałały:sudo chown -R 1000:1000(wyzwalacz:events/solaria/evt-solaria-1785946768-node_health-node.json) isudo chmod -R 775(wyzwalacze:actions/dispatch/lustro,actions/deploy). Ten drugi ustawiłbydispatch/lustrona 775 z zupełnie innego powodu niż fix w executorze, zacierając stan wejściowy testu, i nadałby 775 plikom w całym drzewie runtime (stąd-rwxrwxr-xna heartbeatach i JSON-ach akcji). Świadoma decyzja operatora: nie naprawiać ręcznie. Control-plane zdeployowano samym krokiem compose (up -d --build --force-recreate) — bez sudo, więc rozjazdy chown/chmod zostały nietknięte i czekają na przegląd. Dodatkowosudona VPS wymaga hasła, więc kanoniczna ścieżka i tak kończyłaby się handoffem (exit 5).- Lokalny control-plane na SOLARII (executor/observer/supervisor/ui,
dispatch/solaria/z 2026-07-22) ma nadal executor z bugiem0o755. Nie jest dyspozytorem floty — log to sameStarting executor loop— ale to drugi, niezdeployowany egzemplarz tego samego kodu. Osobna sesja. - LUSTRO i PIHA bez dzisiejszego node-agenta. LUSTRO:
fee079e8. Bez R-fixu rc=23 nadal połykają nieudany unlink — dziś to nie boli, bo executor już nie tworzy złych inboxów, ale każdy przyszły wyciec o innej przyczynie znowu będzie niewidoczny. - Brak pytest w main checkoucie na SOLARII —
deploy.sh <target>przewróciłby się na gate (exit 2) bez--no-gate. Do naprawy, zanim ktoś sięgnie po kanoniczną ścieżkę deployu z tej maszyny. watchtowerna LUSTRO w crash-loopie — 137 restartów,restart=always, próbuje pullnąć lokalnie zbudowanypiper-tts-rpi5:latestz Docker Huba i dostaje 401. Niezwiązane z tym deployem, ale generuje WARNING co 60 s w logach node-agenta.- Duplikat akcji testowej —
container-restart-lustro-node-exporter-dispatchfix.jsonleży jednocześnie wcompleted/(właściwy przebieg) i wcancelled/(kopia z auto-anulowania sprzed approvalu). Pozostawione bez zmian — kosmetyka, żaden zapis produkcyjny nie był potrzebny.
Narrative
user-provided summary