docs: przenies log sesji 15:25 do 2026-08-06.md jako druga sekcje dnia
Tresc byla w osobnym pliku 2026-08-07.md (8031396) mimo ze praca odbyla sie 2026-08-06 — data przyszla stad, ze 2026-08-06.md byl juz zajety przez sesje fazy mailowej. Sesja 15:25 domyka jednak follow-upy #1 i #5 tamtej sesji, wiec jej miejsce jest w tym samym logu dnia, pod naglowkiem `## Session 15:25`, zgodnie z konwencja z 2026-08-05.md. Nie robie tego amendem:8031396zdazyl trafic na origin (operator zmergowal task/mail-sync-impl fast-forwardem ponad nim), wiec historia jest juz publiczna. Przy przenoszeniu doszla korekta sekcji "Sprzatanie" z sesji 13:20: wpis "actions/dispatch/lustro/ — oproznione przez operatora (zombie re-pull ustal)" nie odpowiadal stanowi faktycznemu. O 13:16 oba pliki (10:39 i 11:08) nadal lezaly w zrodle, a LUSTRO re-pullowalo je co 60 s az do 13:18:23. Katalog zdrenowal sie dopiero w wyniku testu z tej sesji — i mogl, bo dopiero wtedy fix w executorze nadal mu prawa 775. Follow-upy sesji 15:25 numerowane osobno (15:25/#1..#5), zeby nie kolidowac z lista z 13:20. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ae16deb8d3
commit
428fd8e8fb
|
|
@ -289,3 +289,208 @@ nigdzie nie prowadzą, i jest głównym powodem, dla którego `events/lustro/` m
|
||||||
### Narrative
|
### Narrative
|
||||||
|
|
||||||
> _user-provided summary_
|
> _user-provided summary_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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`). Domyka follow-upy
|
||||||
|
#1 i #5 z sesji 13:20.
|
||||||
|
|
||||||
|
### 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 15:25/#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
|
||||||
|
oznaczony `U` (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 15:25/#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 |
|
||||||
|
|
||||||
|
**Korekta do sekcji „Sprzątanie" z sesji 13:20.** Zapis „`actions/dispatch/lustro/` na VPS
|
||||||
|
— opróżniony przez operatora (zombie re-pull ustał)" **nie odzwierciedla stanu
|
||||||
|
faktycznego**: o 13:16 oba pliki (z 10:39 i 11:08) nadal leżały w źródle, a LUSTRO
|
||||||
|
re-pullowało je co 60 s aż do 13:18:23. Katalog zdrenował się dopiero w wyniku poniższego
|
||||||
|
testu — i mógł, bo dopiero wtedy miał prawa `775`.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```
|
||||||
|
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` — root cause opisany w KROKU 4b sesji
|
||||||
|
13:20), 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ąć. To
|
||||||
|
dokładnie zjawisko z sekcji „Obserwacja uboczna: regeneracja i auto-cancel" sesji 13:20,
|
||||||
|
tym razem szybsze (7 s vs 15 s). 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:
|
||||||
|
|
||||||
|
1. **755 → 775** dokładnie w momencie zapisu przez executora (13:17:23) ✅
|
||||||
|
2. plik akcji **zniknął** ze źródła po pobraniu i **nie wrócił** w kolejnych cyklach ✅
|
||||||
|
3. **oba zaległe pliki zdrenowane przy okazji** — `dispatch/lustro/` całkowicie pusty ✅
|
||||||
|
4. spam `already processed — skipping` **ustał**: dwa pełne cykle (13:19:25, 13:20:28) z
|
||||||
|
zerem trafień ✅
|
||||||
|
5. akcja `completed` przez `action_result` po 70 s, `node-exporter` z nowym uptime ✅
|
||||||
|
6. 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 15:25/#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 (sesja 15:25)
|
||||||
|
|
||||||
|
1. **`deploy-local.sh` robi rekurencyjny `chown` + `chmod` na 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`) i
|
||||||
|
`sudo chmod -R 775` (wyzwalacze: `actions/dispatch/lustro`, `actions/deploy`). Ten drugi
|
||||||
|
ustawiłby `dispatch/lustro` na 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-x` na 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. Dodatkowo `sudo` na VPS wymaga hasła, więc kanoniczna ścieżka i tak kończyłaby
|
||||||
|
się handoffem (exit 5).
|
||||||
|
2. **Lokalny control-plane na SOLARII** (executor/observer/supervisor/ui, `dispatch/solaria/`
|
||||||
|
z 2026-07-22) ma nadal executor z bugiem `0o755`. Nie jest dyspozytorem floty — log to
|
||||||
|
same `Starting executor loop` — ale to drugi, niezdeployowany egzemplarz tego samego
|
||||||
|
kodu. Osobna sesja.
|
||||||
|
3. **LUSTRO i PIHA bez dzisiejszego node-agenta.** LUSTRO: `fee079e8`. Bez 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 wyciek o innej przyczynie znowu będzie niewidoczny.
|
||||||
|
4. **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.
|
||||||
|
5. **Duplikat akcji testowej** — `container-restart-lustro-node-exporter-dispatchfix.json`
|
||||||
|
leży jednocześnie w `completed/` (właściwy przebieg) i w `cancelled/` (kopia z
|
||||||
|
auto-anulowania sprzed approvalu). Pozostawione bez zmian — kosmetyka, żaden zapis
|
||||||
|
produkcyjny nie był potrzebny.
|
||||||
|
|
||||||
|
### Narrative
|
||||||
|
|
||||||
|
> _user-provided summary_
|
||||||
|
|
|
||||||
|
|
@ -1,214 +0,0 @@
|
||||||
---
|
|
||||||
okf: "0.1"
|
|
||||||
type: session-log
|
|
||||||
visibility: private
|
|
||||||
status: active
|
|
||||||
updated: 2026-08-06
|
|
||||||
links: []
|
|
||||||
---
|
|
||||||
|
|
||||||
# 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.md` jest 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
|
|
||||||
oznaczony `U` (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:
|
|
||||||
|
|
||||||
1. **755 → 775** dokładnie w momencie zapisu przez executora (13:17:23) ✅
|
|
||||||
2. plik akcji **zniknął** ze źródła po pobraniu i **nie wrócił** w kolejnych cyklach ✅
|
|
||||||
3. **oba zaległe pliki zdrenowane przy okazji** — `dispatch/lustro/` całkowicie pusty ✅
|
|
||||||
4. spam `already processed — skipping` **ustał**: dwa pełne cykle (13:19:25, 13:20:28) z
|
|
||||||
zerem trafień ✅
|
|
||||||
5. akcja `completed` przez `action_result` po 70 s, `node-exporter` z nowym uptime ✅
|
|
||||||
6. 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
|
|
||||||
|
|
||||||
1. **`deploy-local.sh` robi rekurencyjny `chown` + `chmod` na 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`) i
|
|
||||||
`sudo chmod -R 775` (wyzwalacze: `actions/dispatch/lustro`, `actions/deploy`). Ten drugi
|
|
||||||
ustawiłby `dispatch/lustro` na 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-x` na 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. Dodatkowo `sudo` na VPS wymaga hasła, więc kanoniczna ścieżka i tak kończyłaby
|
|
||||||
się handoffem (exit 5).
|
|
||||||
2. **Lokalny control-plane na SOLARII** (executor/observer/supervisor/ui, `dispatch/solaria/`
|
|
||||||
z 2026-07-22) ma nadal executor z bugiem `0o755`. Nie jest dyspozytorem floty — log to
|
|
||||||
same `Starting executor loop` — ale to drugi, niezdeployowany egzemplarz tego samego
|
|
||||||
kodu. Osobna sesja.
|
|
||||||
3. **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.
|
|
||||||
4. **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.
|
|
||||||
5. **`watchtower` na LUSTRO w crash-loopie** — 137 restartów, `restart=always`, próbuje
|
|
||||||
pullnąć lokalnie zbudowany `piper-tts-rpi5:latest` z Docker Huba i dostaje 401.
|
|
||||||
Niezwiązane z tym deployem, ale generuje WARNING co 60 s w logach node-agenta.
|
|
||||||
6. **Duplikat akcji testowej** — `container-restart-lustro-node-exporter-dispatchfix.json`
|
|
||||||
leży jednocześnie w `completed/` (właściwy przebieg) i w `cancelled/` (kopia z
|
|
||||||
auto-anulowania sprzed approvalu). Pozostawione bez zmian — kosmetyka, żaden zapis
|
|
||||||
produkcyjny nie był potrzebny.
|
|
||||||
|
|
||||||
### Narrative
|
|
||||||
|
|
||||||
> _user-provided summary_
|
|
||||||
Loading…
Reference in a new issue