Compare commits
10 commits
fd6b6a547a
...
32b3643b8a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32b3643b8a | ||
|
|
a6cdc2356b | ||
|
|
6dffa5c565 | ||
|
|
8d601e14b0 | ||
|
|
ff56a3430c | ||
|
|
cb48ca0f94 | ||
|
|
b996c9c774 | ||
|
|
136bdb563b | ||
|
|
c0fa8d83fc | ||
|
|
b90b60bee4 |
|
|
@ -93,7 +93,7 @@ services:
|
||||||
|
|
||||||
preflight fills `arch`, `ram_mb`, `docker_present`, `mm_runtime` — do NOT guess these.
|
preflight fills `arch`, `ram_mb`, `docker_present`, `mm_runtime` — do NOT guess these.
|
||||||
|
|
||||||
Full schema: `scripts/onboard/README.md`.
|
Full schema: `kb/runbooks/node-onboarding-tool.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ Pipeline stages: **prepare → validate → deploy → verify → diagnose (on f
|
||||||
## Node Onboarding
|
## Node Onboarding
|
||||||
|
|
||||||
New nodes are onboarded via `scripts/onboard/` — an idempotent bash tool driven by
|
New nodes are onboarded via `scripts/onboard/` — an idempotent bash tool driven by
|
||||||
`hosts/<node>/node.yaml` manifests (no Ansible). See `scripts/onboard/README.md` for
|
`hosts/<node>/node.yaml` manifests (no Ansible). See `kb/runbooks/node-onboarding-tool.md` for
|
||||||
the full schema, step status table, and gotchas.
|
the full schema, step status table, and gotchas.
|
||||||
|
|
||||||
Key fields in `node.yaml`: `ssh_user`, `first_contact` (LAN IP — not `.local`),
|
Key fields in `node.yaml`: `ssh_user`, `first_contact` (LAN IP — not `.local`),
|
||||||
|
|
@ -93,7 +93,7 @@ Agent → /opt/homelab/actions/pending/<id>.json
|
||||||
→ Executor dispatches to the target node → completed / failed
|
→ Executor dispatches to the target node → completed / failed
|
||||||
```
|
```
|
||||||
|
|
||||||
The executor never connects to a node (deliberate — see docs/backlog.md
|
The executor never connects to a node (deliberate — see kb/phases/backlog.md
|
||||||
"Remediacja floty bez SSH"). It writes a dispatch file that the node collects:
|
"Remediacja floty bez SSH"). It writes a dispatch file that the node collects:
|
||||||
|
|
||||||
| Action type | Inbox | Executed on the node by |
|
| Action type | Inbox | Executed on the node by |
|
||||||
|
|
|
||||||
26
README.md
26
README.md
|
|
@ -31,29 +31,29 @@ Action approval flow: `pending/` → operator approves → `approved/` → execu
|
||||||
|
|
||||||
## Repository Structure
|
## Repository Structure
|
||||||
|
|
||||||
- `docs/`: [Infrastructure Standards](docs/standards.md) and [Deployment Conventions](docs/deployment.md).
|
- `docs/`: [Infrastructure Standards](kb/subsystems/standards.md) and [Deployment Conventions](kb/subsystems/deployment.md).
|
||||||
- `docs/architecture/PLAN-subsystem-a-2026-07-28.md`: [Current Maintenance Plan (Control Plane)](docs/architecture/PLAN-subsystem-a-2026-07-28.md).
|
- `kb/phases/subsystem-a-naprawa.md`: [Current Maintenance Plan (Control Plane)](kb/phases/subsystem-a-naprawa.md).
|
||||||
- `hosts/`: Host-specific configurations and service assignments.
|
- `hosts/`: Host-specific configurations and service assignments.
|
||||||
- `services/`: Reusable Docker Compose service definitions.
|
- `services/`: Reusable Docker Compose service definitions.
|
||||||
- `scripts/`: Deployment and management scripts.
|
- `scripts/`: Deployment and management scripts.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
1. **Standardization**: Follow the [Infrastructure Standards](docs/standards.md).
|
1. **Standardization**: Follow the [Infrastructure Standards](kb/subsystems/standards.md).
|
||||||
2. **Deployment**: See [Deployment Conventions](docs/deployment.md) for how to roll out changes.
|
2. **Deployment**: See [Deployment Conventions](kb/subsystems/deployment.md) for how to roll out changes.
|
||||||
3. **SATURN**: Remember that SATURN is the only node where commits should be made.
|
3. **SATURN**: Remember that SATURN is the only node where commits should be made.
|
||||||
|
|
||||||
## Documentation Index
|
## Documentation Index
|
||||||
|
|
||||||
- [Current Maintenance Plan (Control Plane)](docs/architecture/PLAN-subsystem-a-2026-07-28.md)
|
- [Current Maintenance Plan (Control Plane)](kb/phases/subsystem-a-naprawa.md)
|
||||||
- [Infrastructure Standards](docs/standards.md)
|
- [Infrastructure Standards](kb/subsystems/standards.md)
|
||||||
- [Agent Operating Procedures](docs/agents.md) (For AI/Non-Human Agents)
|
- [Agent Operating Procedures](kb/subsystems/agent-operating-procedures.md) (For AI/Non-Human Agents)
|
||||||
- [Deployment Conventions](docs/deployment.md)
|
- [Deployment Conventions](kb/subsystems/deployment.md)
|
||||||
- [Hardware](docs/hardware.md)
|
- [Hardware](kb/nodes/legacy-hardware.md)
|
||||||
- [Networking](docs/networking.md)
|
- [Networking](kb/subsystems/networking.md)
|
||||||
- [Services](docs/services.md)
|
- [Services](kb/subsystems/legacy-services-list.md)
|
||||||
- [Node Capabilities](docs/capabilities.md)
|
- [Node Capabilities](kb/subsystems/capability-model.md)
|
||||||
- [Action Model](services/agent-system/action-model.md)
|
- [Action Model](kb/subsystems/action-approval-model.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
*Note: This repository documents the state of the homelab. Runtime state lives outside the repository in `/opt/homelab`.*
|
*Note: This repository documents the state of the homelab. Runtime state lives outside the repository in `/opt/homelab`.*
|
||||||
|
|
|
||||||
1354
docs/backlog.md
1354
docs/backlog.md
File diff suppressed because it is too large
Load diff
|
|
@ -1,65 +0,0 @@
|
||||||
# Unknowns and Clarification Questions
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
This page lists information that is missing or unclear from the current homelab documentation.
|
|
||||||
|
|
||||||
## Current configuration
|
|
||||||
|
|
||||||
The currently documented configuration is limited to:
|
|
||||||
|
|
||||||
- Raspberry Pi 5 as the main server.
|
|
||||||
- Docker, Portainer, and Nginx Proxy Manager as the core stack.
|
|
||||||
- NAT with forwarded ports:
|
|
||||||
- `80-81` to `4480-4481`
|
|
||||||
- `443` to `4443`
|
|
||||||
- Public access through Nginx Proxy Manager with Let's Encrypt HTTPS.
|
|
||||||
- Private access through Tailscale.
|
|
||||||
- Hetzner VPS handoff:
|
|
||||||
- Hostname: `ubuntu-4gb-hel1-1`
|
|
||||||
- Tailscale IP: `100.95.58.48`
|
|
||||||
- Public IPv4: `135.181.153.108`
|
|
||||||
- Public IPv6: `2a01:4f9:c014:98f0::1`
|
|
||||||
- Running container: `npm`
|
|
||||||
- Joplin files created but not running.
|
|
||||||
|
|
||||||
## Known facts
|
|
||||||
|
|
||||||
- The homelab is documented only from the known facts above.
|
|
||||||
- Anything not listed as known remains unconfirmed.
|
|
||||||
|
|
||||||
## Unknown / needs clarification
|
|
||||||
|
|
||||||
1. What operating system and version is running on the Raspberry Pi 5?
|
|
||||||
2. What is the Raspberry Pi 5 RAM size?
|
|
||||||
3. What storage devices are used, and where is persistent service data stored?
|
|
||||||
4. What is the Raspberry Pi 5 LAN IP address?
|
|
||||||
5. Is the Raspberry Pi 5 using DHCP or a static IP address?
|
|
||||||
6. What router or firewall performs NAT and port forwarding?
|
|
||||||
7. Is the WAN IP static, dynamic, or behind CGNAT?
|
|
||||||
8. Does external port `80` map to internal port `4480`, and does external port `81` map to internal port `4481`?
|
|
||||||
9. Are the forwarded ports TCP only, UDP only, or both?
|
|
||||||
10. Are any other ports forwarded?
|
|
||||||
11. What domain names or subdomains point to the homelab?
|
|
||||||
12. What are the Nginx Proxy Manager proxy hosts?
|
|
||||||
13. Which services are public, and which are private-only?
|
|
||||||
14. Is HTTP-to-HTTPS redirection enabled in Nginx Proxy Manager?
|
|
||||||
15. Are Nginx Proxy Manager access lists used?
|
|
||||||
16. How are Docker, Portainer, and Nginx Proxy Manager deployed?
|
|
||||||
17. Are Docker Compose files, Portainer stacks, or other manifests available?
|
|
||||||
18. What containers are currently running?
|
|
||||||
19. What Docker networks and volumes exist?
|
|
||||||
20. What is the Tailscale device name for the Raspberry Pi 5?
|
|
||||||
21. Does the Raspberry Pi 5 advertise Tailscale subnet routes?
|
|
||||||
22. Is the Raspberry Pi 5 configured as a Tailscale exit node?
|
|
||||||
23. Is Tailscale SSH enabled?
|
|
||||||
24. What backup system exists, if any?
|
|
||||||
25. What monitoring or alerting exists, if any?
|
|
||||||
26. Is the Hetzner VPS part of the homelab documentation scope, a separate system, or both?
|
|
||||||
27. What is the operating system version on `ubuntu-4gb-hel1-1`?
|
|
||||||
28. Is public Nginx Proxy Manager admin access on port `81` intentionally reachable on `135.181.153.108`?
|
|
||||||
29. Has DNS record `joplin.okit.pl -> 135.181.153.108` been created?
|
|
||||||
30. Has optional AAAA record `joplin.okit.pl -> 2a01:4f9:c014:98f0::1` been created?
|
|
||||||
31. Has `POSTGRES_PASSWORD=CHANGE_ME_STRONG_PASSWORD` been changed before first Joplin production start?
|
|
||||||
32. Has the Nginx Proxy Manager proxy host for `joplin.okit.pl` been created?
|
|
||||||
33. Are ports `80` and `443` publicly reachable on the Hetzner VPS for Let's Encrypt HTTP validation?
|
|
||||||
|
|
@ -90,7 +90,7 @@ przez Tailscale działa bezhasłowo. Verify czysty (arch=aarch64).
|
||||||
|
|
||||||
## Learnings
|
## Learnings
|
||||||
|
|
||||||
(odzwierciedlone też w `scripts/onboard/README.md`)
|
(odzwierciedlone też w `kb/runbooks/node-onboarding-tool.md`)
|
||||||
|
|
||||||
- mDNS `.local` zawodny do automatyzacji → `first_contact` przez IP lub tailscale, nie `.local`
|
- mDNS `.local` zawodny do automatyzacji → `first_contact` przez IP lub tailscale, nie `.local`
|
||||||
- istniejący node z userem uid=1000: użyj go zamiast tworzyć `oskar` (kolizja uid)
|
- istniejący node z userem uid=1000: użyj go zamiast tworzyć `oskar` (kolizja uid)
|
||||||
|
|
|
||||||
|
|
@ -130,4 +130,4 @@ Docelowo: osobny worktree per task.
|
||||||
|
|
||||||
## Tech-debt złapany w sesji
|
## Tech-debt złapany w sesji
|
||||||
|
|
||||||
→ wpisany do `docs/backlog.md`
|
→ wpisany do `kb/phases/backlog.md`
|
||||||
|
|
|
||||||
|
|
@ -79,13 +79,13 @@ solaria / piha / chelsty to wciąż **stare root kontenery** node-agenta
|
||||||
(piha Created 2026-05-27, uid 0). Ich mount `/root/.ssh` działa tylko dlatego,
|
(piha Created 2026-05-27, uid 0). Ich mount `/root/.ssh` działa tylko dlatego,
|
||||||
że kontenery są sprzed `user: "1000:1000"`. Pierwszy `--force-recreate` / reboot
|
że kontenery są sprzed `user: "1000:1000"`. Pierwszy `--force-recreate` / reboot
|
||||||
hosta / update obrazu przełączy je na uid 1000 i shipping padnie jak na lustrze.
|
hosta / update obrazu przełączy je na uid 1000 i shipping padnie jak na lustrze.
|
||||||
**NIE RECREATE bez fixu.** Szczegóły i fix: `docs/backlog.md`.
|
**NIE RECREATE bez fixu.** Szczegóły i fix: `kb/phases/backlog.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tech-debt złapany w sesji
|
## Tech-debt złapany w sesji
|
||||||
|
|
||||||
→ wpisany do `docs/backlog.md` (flota-bomba, ha-diag-agent blocked,
|
→ wpisany do `kb/phases/backlog.md` (flota-bomba, ha-diag-agent blocked,
|
||||||
poison-quarantine review, `--omit-dir-times`, stale komentarz node_agent.py,
|
poison-quarantine review, `--omit-dir-times`, stale komentarz node_agent.py,
|
||||||
shipping success na `logger.debug`, event-bloat lustro na VPS).
|
shipping success na `logger.debug`, event-bloat lustro na VPS).
|
||||||
|
|
||||||
|
|
@ -96,8 +96,8 @@ fa59625 docs(ha-diag-agent): replace curl verify commands with docker exec
|
||||||
d7e0d31 fix(ha-diag-agent): remove host port mapping for 8087
|
d7e0d31 fix(ha-diag-agent): remove host port mapping for 8087
|
||||||
|
|
||||||
### Files changed
|
### Files changed
|
||||||
services/ha-diag-agent/DEPLOY.md | 4 ++--
|
kb/runbooks/ha-diag-agent-deploy.md | 4 ++--
|
||||||
services/ha-diag-agent/README.md | 4 ++--
|
kb/services/ha-diag-agent.md | 4 ++--
|
||||||
services/ha-diag-agent/docker-compose.yml | 3 ---
|
services/ha-diag-agent/docker-compose.yml | 3 ---
|
||||||
services/ha-diag-agent/service.yaml | 3 ---
|
services/ha-diag-agent/service.yaml | 3 ---
|
||||||
4 files changed, 4 insertions(+), 10 deletions(-))
|
4 files changed, 4 insertions(+), 10 deletions(-))
|
||||||
|
|
|
||||||
|
|
@ -120,14 +120,14 @@ services/kb-postgres/service.yaml
|
||||||
services/kb-postgres/env.example
|
services/kb-postgres/env.example
|
||||||
services/kb-postgres/healthcheck.sh
|
services/kb-postgres/healthcheck.sh
|
||||||
services/kb-postgres/init/001_envelope.sql
|
services/kb-postgres/init/001_envelope.sql
|
||||||
services/kb-postgres/README.md
|
kb/services/kb-postgres.md
|
||||||
hosts/solaria/runtime/kb-postgres/docker-compose.override.yml
|
hosts/solaria/runtime/kb-postgres/docker-compose.override.yml
|
||||||
hosts/solaria/services.yaml
|
hosts/solaria/services.yaml
|
||||||
inventory/topology.yaml
|
inventory/topology.yaml
|
||||||
packages/kb-mail/pyproject.toml
|
packages/kb-mail/pyproject.toml
|
||||||
packages/kb-mail/src/kb_mail/{__init__,envelope,db,archive}.py
|
packages/kb-mail/src/kb_mail/{__init__,envelope,db,archive}.py
|
||||||
packages/kb-mail/tests/{conftest,test_envelope,test_archive,test_db,test_migration}.py
|
packages/kb-mail/tests/{conftest,test_envelope,test_archive,test_db,test_migration}.py
|
||||||
docs/kb/kb-00-overview.md (etap 1 done, konwencja packages/)
|
kb/subsystems/kb-overview.md (etap 1 done, konwencja packages/)
|
||||||
CLAUDE.md (sekcja Shared Python Libraries)
|
CLAUDE.md (sekcja Shared Python Libraries)
|
||||||
docs/sessions/2026-06-17-kb-foundations.md
|
docs/sessions/2026-06-17-kb-foundations.md
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ jobs/gmail-bulk-import/pyproject.toml
|
||||||
jobs/gmail-bulk-import/tests/test_importer.py
|
jobs/gmail-bulk-import/tests/test_importer.py
|
||||||
hosts/piha/capabilities.yaml
|
hosts/piha/capabilities.yaml
|
||||||
.gitignore
|
.gitignore
|
||||||
docs/kb/kb-00-overview.md (etap 2 gotowy, konwencja jobs/)
|
kb/subsystems/kb-overview.md (etap 2 gotowy, konwencja jobs/)
|
||||||
docs/kb/kb-01-email-design.md (§8 krok 2 = kod gotowy)
|
kb/subsystems/kb-mail-pillar.md (§8 krok 2 = kod gotowy)
|
||||||
docs/sessions/2026-06-24-kb-gmail-importer.md
|
docs/sessions/2026-06-24-kb-gmail-importer.md
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ docker compose \
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Nowe tech-debty (dodane do `docs/backlog.md`)
|
## Nowe tech-debty (dodane do `kb/phases/backlog.md`)
|
||||||
|
|
||||||
1. **Rozjazd stanu Docker Compose na VPS** — serwisy `node-agent`, `control-plane` i inne
|
1. **Rozjazd stanu Docker Compose na VPS** — serwisy `node-agent`, `control-plane` i inne
|
||||||
stworzone innym `project-name` niż `deploy-node.sh` oczekuje; Recreate pada na stale
|
stworzone innym `project-name` niż `deploy-node.sh` oczekuje; Recreate pada na stale
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ architekturą dokumentów KB. Start od weryfikacji stanu faktycznego wszystkich
|
||||||
- CC (Sonnet 4.6) w worktree `fleet-inventory` zebrał stan faktyczny (docker ps +
|
- CC (Sonnet 4.6) w worktree `fleet-inventory` zebrał stan faktyczny (docker ps +
|
||||||
free/df/nproc) z 4 dostępnych nodów: PIHA, VPS, SOLARIA, SATURN. LUSTRO+CHELSTY
|
free/df/nproc) z 4 dostępnych nodów: PIHA, VPS, SOLARIA, SATURN. LUSTRO+CHELSTY
|
||||||
offline (timeout :22) -> oznaczone UNREACHABLE.
|
offline (timeout :22) -> oznaczone UNREACHABLE.
|
||||||
- Wynik: `docs/infra/inventory-2026-06-30.md` — 23 zpriorytetyzowane rozjazdy.
|
- Wynik: `kb/subsystems/fleet-inventory.md` — 23 zpriorytetyzowane rozjazdy.
|
||||||
- Kluczowe ustalenia:
|
- Kluczowe ustalenia:
|
||||||
- **forgejo** biega na PIHA (always-on), ale `service.yaml owner_node=saturn` — rozjazd
|
- **forgejo** biega na PIHA (always-on), ale `service.yaml owner_node=saturn` — rozjazd
|
||||||
- **mosquitto** biega na VPS, `service.yaml owner=piha`, na PIHA go nie ma
|
- **mosquitto** biega na VPS, `service.yaml owner=piha`, na PIHA go nie ma
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ links: []
|
||||||
# Sesja 2026-07-02 — Modul 0 (odchudzenie PIHA) + migracja Forgejo/Vikunja na kapala.org
|
# Sesja 2026-07-02 — Modul 0 (odchudzenie PIHA) + migracja Forgejo/Vikunja na kapala.org
|
||||||
|
|
||||||
## Modul 0 kb-02 — WYKONANY (faza 1 audyt + faza 2 egzekucja)
|
## Modul 0 kb-02 — WYKONANY (faza 1 audyt + faza 2 egzekucja)
|
||||||
- Audyt CC (read-only): docs/infra/piha-slim-audit-2026-07-02.md
|
- Audyt CC (read-only): kb/audits/piha-slim-2026-07-02.md
|
||||||
- Review Oskara skorygowal audyt: llm-gateway = WLASNY kod (FastAPI-router LLM,
|
- Review Oskara skorygowal audyt: llm-gateway = WLASNY kod (FastAPI-router LLM,
|
||||||
/opt/llm-gateway, proxy do Ollama@SOLARIA) — NIE martwy; immich MUSI byc 24/7
|
/opt/llm-gateway, proxy do Ollama@SOLARIA) — NIE martwy; immich MUSI byc 24/7
|
||||||
na PIHA (SOLARIA sesyjna) — rekomendacja przeniesienia wykreslona.
|
na PIHA (SOLARIA sesyjna) — rekomendacja przeniesienia wykreslona.
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ Sesja tylko-recon + minimalne fixy; bez deployów nowych feature'ów.
|
||||||
|
|
||||||
### Recon-weryfikacja inwentaryzacji floty (commit `57a6dff`, read-only)
|
### Recon-weryfikacja inwentaryzacji floty (commit `57a6dff`, read-only)
|
||||||
|
|
||||||
Wynik: `docs/infra/inventory-verify-2026-07-02.md`.
|
Wynik: `kb/subsystems/fleet-inventory-verify.md`.
|
||||||
|
|
||||||
**Bilans 23 rozjazdów z audytu 2026-06-30**:
|
**Bilans 23 rozjazdów z audytu 2026-06-30**:
|
||||||
- **20 wciąż aktualnych** — nic się samo nie naprawiło.
|
- **20 wciąż aktualnych** — nic się samo nie naprawiło.
|
||||||
|
|
@ -100,7 +100,7 @@ Po jednej linii per plik; `owner_node` nie występował nigdzie indziej w repo.
|
||||||
nie rezolwuje z SOLARII; brak formalnego override mem_limit fleet-prometheus
|
nie rezolwuje z SOLARII; brak formalnego override mem_limit fleet-prometheus
|
||||||
w `hosts/vps/runtime/` (siedzi w bazowym compose — kosmetyka).
|
w `hosts/vps/runtime/` (siedzi w bazowym compose — kosmetyka).
|
||||||
|
|
||||||
Wpisy dodane do `docs/backlog.md` w tej sesji.
|
Wpisy dodane do `kb/phases/backlog.md` w tej sesji.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ Prometheus → brain-watchdog → Telegram, którego brakowało od 2026-06-30.
|
||||||
|
|
||||||
### Recon cutoveru — wmergowany (commit `d94bb38`)
|
### Recon cutoveru — wmergowany (commit `d94bb38`)
|
||||||
|
|
||||||
Wynik: `docs/infra/prometheus-cutover-recon-2026-07-06.md` (517 linii, read-only,
|
Wynik: `kb/audits/prometheus-cutover-2026-07-06.md` (517 linii, read-only,
|
||||||
zero zmian w kodzie). Kluczowe ustalenia:
|
zero zmian w kodzie). Kluczowe ustalenia:
|
||||||
|
|
||||||
- **Cutover to podmiana klasyfikacji liveności w JEDNYM miejscu** —
|
- **Cutover to podmiana klasyfikacji liveności w JEDNYM miejscu** —
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ maila = ta sama encja, DOWOD zasady kb-00 #7), (3) interfejs pytan (RAG) — pie
|
||||||
realnej uzytecznosci. Dopiero POTEM dopelniac importy (reszta Takeout, zdjecia, transakcje).
|
realnej uzytecznosci. Dopiero POTEM dopelniac importy (reszta Takeout, zdjecia, transakcje).
|
||||||
|
|
||||||
## TODO nastepne
|
## TODO nastepne
|
||||||
- MODUL 5 (koperta + ingest + embeddingi + cross-source) — docs/kb/modules/05-documents-ingest.md
|
- MODUL 5 (koperta + ingest + embeddingi + cross-source) — kb/phases/kb-m5-documents-ingest.md
|
||||||
- Import probki zalacznikow z maili (kilkaset, nie 70k) — do zbudowania RAG
|
- Import probki zalacznikow z maili (kilkaset, nie 70k) — do zbudowania RAG
|
||||||
- Interfejs pytan / RAG — warstwa uzytkowa
|
- Interfejs pytan / RAG — warstwa uzytkowa
|
||||||
- Deploy 3 (Nextcloud), Deploy 4 (Gokapi) — configi gotowe, czekaja
|
- Deploy 3 (Nextcloud), Deploy 4 (Gokapi) — configi gotowe, czekaja
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@ parsowany z nazwy `evt-<node>-<ts>-...` (fallback mtime, **nigdy 0** dla
|
||||||
istniejącego pliku — 0 = leksykalne "starszy niż checkpoint" = dokładnie ten
|
istniejącego pliku — 0 = leksykalne "starszy niż checkpoint" = dokładnie ten
|
||||||
poison), migracja starych path-checkpointów przy starcie. Zdeployowany na VPS
|
poison), migracja starych path-checkpointów przy starcie. Zdeployowany na VPS
|
||||||
(observer `StartedAt` 07-14). Zweryfikowany dziś jako kompletny i zdeployowany.
|
(observer `StartedAt` 07-14). Zweryfikowany dziś jako kompletny i zdeployowany.
|
||||||
Szczegóły: `docs/backlog.md` (sekcja "Bug: checkpoint observera po ścieżce
|
Szczegóły: `kb/phases/backlog.md` (sekcja "Bug: checkpoint observera po ścieżce
|
||||||
leksykalnej").
|
leksykalnej").
|
||||||
|
|
||||||
### 2. docs(infra) analiza Etapu 2 shadow-run (Fable, `8fec62d`)
|
### 2. docs(infra) analiza Etapu 2 shadow-run (Fable, `8fec62d`)
|
||||||
|
|
||||||
`docs/infra/prometheus-shadow-etap2-analiza-2026-07-15.md` — 165 mismatchy
|
`kb/phases/prometheus-cutover-etap2.md` — 165 mismatchy
|
||||||
`SHADOW_LIVENESS_MISMATCH` solaria/lustro w dobie 2026-07-14 WYJAŚNIONE: dwa
|
`SHADOW_LIVENESS_MISMATCH` solaria/lustro w dobie 2026-07-14 WYJAŚNIONE: dwa
|
||||||
nocne wyłączenia węzłów (lustro 21:30 UTC — regularny power-off, solaria
|
nocne wyłączenia węzłów (lustro 21:30 UTC — regularny power-off, solaria
|
||||||
21:34 UTC). Wzorzec `event=fresh prom=down` to **nie** "żywy węzeł niewidziany
|
21:34 UTC). Wzorzec `event=fresh prom=down` to **nie** "żywy węzeł niewidziany
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ links: []
|
||||||
|
|
||||||
### 1. RECON lustro shipping (Fable, commit `542bba4`)
|
### 1. RECON lustro shipping (Fable, commit `542bba4`)
|
||||||
|
|
||||||
`docs/infra/lustro-shipping-recon-2026-07-16.md` — 1507 mismatchy `lustro event=dead prom=up` w trwałym logu WYJAŚNIONE: (a) wczorajszy kontrolowany test (node-agent stał 3h20m, nie 15 min jak zakładano) + (b) poranny boot-race 56s. **Werdykt: shipping lustro działa, ZERO recurring problemu.** Prometheus 0 pomyłek w 48h — wzmacnia rekomendację GO dla Etapu 3 cutoveru.
|
`kb/audits/lustro-shipping-2026-07-16.md` — 1507 mismatchy `lustro event=dead prom=up` w trwałym logu WYJAŚNIONE: (a) wczorajszy kontrolowany test (node-agent stał 3h20m, nie 15 min jak zakładano) + (b) poranny boot-race 56s. **Werdykt: shipping lustro działa, ZERO recurring problemu.** Prometheus 0 pomyłek w 48h — wzmacnia rekomendację GO dla Etapu 3 cutoveru.
|
||||||
|
|
||||||
Znaleziska poboczne: lustro biega na obrazie sprzed 5 tyg (deploy-node bez `--build` — patrz fix #2 niżej); fake-hwclock boot-race (RPi bez RTC — pierwszy event po boocie ma stary stempel, dropnięty przez timestamp checkpoint).
|
Znaleziska poboczne: lustro biega na obrazie sprzed 5 tyg (deploy-node bez `--build` — patrz fix #2 niżej); fake-hwclock boot-race (RPi bez RTC — pierwszy event po boocie ma stary stempel, dropnięty przez timestamp checkpoint).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ approval → executor → node-agent → docker restart → completed.
|
||||||
test E2E padł: agent rzucał `[Errno 13] Permission denied:
|
test E2E padł: agent rzucał `[Errno 13] Permission denied:
|
||||||
/opt/homelab/actions/dispatch` co cykl. Root cause to ZNANY, POWRACAJĄCY
|
/opt/homelab/actions/dispatch` co cykl. Root cause to ZNANY, POWRACAJĄCY
|
||||||
(już 4. raz — patrz sekcja "Tech-debt: globalny porządek uid/gid/uprawnień
|
(już 4. raz — patrz sekcja "Tech-debt: globalny porządek uid/gid/uprawnień
|
||||||
we flocie" w `docs/backlog.md`) motyw
|
we flocie" w `kb/phases/backlog.md`) motyw
|
||||||
uid/gid na PIHA: oskar ma uid 1004, kontener agenta biega jako uid 1000
|
uid/gid na PIHA: oskar ma uid 1004, kontener agenta biega jako uid 1000
|
||||||
(= user `pi` na hoście). `/opt/homelab/actions` było `oskar:oskar
|
(= user `pi` na hoście). `/opt/homelab/actions` było `oskar:oskar
|
||||||
drwxr-xr-x` (utworzone w maju), podczas gdy DZIAŁAJĄCY wzorzec to
|
drwxr-xr-x` (utworzone w maju), podczas gdy DZIAŁAJĄCY wzorzec to
|
||||||
|
|
@ -111,7 +111,7 @@ approval → executor → node-agent → docker restart → completed.
|
||||||
Pierwszy w historii systemu pełny cykl remediacji end-to-end potwierdzony w
|
Pierwszy w historii systemu pełny cykl remediacji end-to-end potwierdzony w
|
||||||
produkcji (PIHA), bez SSH z control-plane do węzłów. Publiczna dziura
|
produkcji (PIHA), bez SSH z control-plane do węzłów. Publiczna dziura
|
||||||
autoryzacji na `operator_ui.py:18180` zamknięta (bind ograniczony do
|
autoryzacji na `operator_ui.py:18180` zamknięta (bind ograniczony do
|
||||||
Tailscale). Otwarte follow-upy — patrz `docs/backlog.md` (retry-w-nieskończoność
|
Tailscale). Otwarte follow-upy — patrz `kb/phases/backlog.md` (retry-w-nieskończoność
|
||||||
zepsutego JSON, uprawnienia `actions/` na innych węzłach, brak twardego checka
|
zepsutego JSON, uprawnienia `actions/` na innych węzłach, brak twardego checka
|
||||||
`.env`/`TAILSCALE_BIND_IP` w `deploy-local.sh`, brak autoryzacji w
|
`.env`/`TAILSCALE_BIND_IP` w `deploy-local.sh`, brak autoryzacji w
|
||||||
`operator_ui.py`, zapchana approval queue przez `alert_only`, brak
|
`operator_ui.py`, zapchana approval queue przez `alert_only`, brak
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ links: []
|
||||||
|
|
||||||
# Sesja 2026-07-23 — KB faza 4: ingress kb.kapala.org (krok 5/§8)
|
# Sesja 2026-07-23 — KB faza 4: ingress kb.kapala.org (krok 5/§8)
|
||||||
|
|
||||||
**Zakres**: wyłącznie ingress (`docs/kb/modules/05-faza4-plan.md` §8, krok 5) —
|
**Zakres**: wyłącznie ingress (`kb/phases/kb-m5-faza4.md` §8, krok 5) —
|
||||||
frontend i `/search` już LIVE na PIHA (port 8230) od sesji 2026-07-22. Zero
|
frontend i `/search` już LIVE na PIHA (port 8230) od sesji 2026-07-22. Zero
|
||||||
zmian w kodzie kb-query w tej sesji.
|
zmian w kodzie kb-query w tej sesji.
|
||||||
|
|
||||||
|
|
@ -70,8 +70,8 @@ w tej samej sesji, osobnym przebiegiem po zgłoszeniu przez operatora:
|
||||||
Potwierdzone w repo (zgodnie z `05-faza4-plan.md` §1.4): **brak wzorca
|
Potwierdzone w repo (zgodnie z `05-faza4-plan.md` §1.4): **brak wzorca
|
||||||
forward-auth/reverse-proxy-level auth** — NPM community edition go nie ma
|
forward-auth/reverse-proxy-level auth** — NPM community edition go nie ma
|
||||||
(sprawdzone: brak `oauth2-proxy`/`authelia`/`forward_auth` w kodzie repo poza
|
(sprawdzone: brak `oauth2-proxy`/`authelia`/`forward_auth` w kodzie repo poza
|
||||||
wzmiankami "przyszła opcja" w `docs/kb/kb-02-documents-design.md` i
|
wzmiankami "przyszła opcja" w `kb/subsystems/kb-documents-pillar.md` i
|
||||||
`hosts/vps/README.md`). Wszystkie 3 precedensy (paperless/nextcloud/vikunja)
|
`kb/nodes/vps.md`). Wszystkie 3 precedensy (paperless/nextcloud/vikunja)
|
||||||
robią OIDC **wewnątrz aplikacji**. kb-query nie ma dziś żadnego logowania.
|
robią OIDC **wewnątrz aplikacji**. kb-query nie ma dziś żadnego logowania.
|
||||||
|
|
||||||
Zgodnie z instrukcją zadania: **nie budowano** nowego komponentu auth.
|
Zgodnie z instrukcją zadania: **nie budowano** nowego komponentu auth.
|
||||||
|
|
@ -122,7 +122,7 @@ username collision, `docs/sessions/2026-07-10-paperless-deploy.md`).
|
||||||
|
|
||||||
## Pliki repo zmienione
|
## Pliki repo zmienione
|
||||||
|
|
||||||
- `services/kb-query/README.md` — sekcja "Ingress" (co żyje, co nie, dlaczego
|
- `kb/services/kb-query.md` — sekcja "Ingress" (co żyje, co nie, dlaczego
|
||||||
auth odłożone) zastępuje starą notatkę "not wired up yet".
|
auth odłożone) zastępuje starą notatkę "not wired up yet".
|
||||||
- `docs/sessions/2026-07-23-kb-f4-ingress.md` — ten dokument.
|
- `docs/sessions/2026-07-23-kb-f4-ingress.md` — ten dokument.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ links: []
|
||||||
|
|
||||||
# Sesja 2026-07-27 — KB faza 4: fallback embed SOLARIA→PIHA (krok 3, ostatni element rdzenia)
|
# Sesja 2026-07-27 — KB faza 4: fallback embed SOLARIA→PIHA (krok 3, ostatni element rdzenia)
|
||||||
|
|
||||||
> **Dopisek redakcyjny (2026-07-30, dedup — `docs/kb/modules/05-fallback-dedup-raport.md`):**
|
> **Dopisek redakcyjny (2026-07-30, dedup — `kb/phases/kb-m5-faza4-fallback-dedup.md`):**
|
||||||
> implementacja kodu z tej sesji (`app/fallback.py`, branch `task/kb-f4-fallback`, 3d4ee38)
|
> implementacja kodu z tej sesji (`app/fallback.py`, branch `task/kb-f4-fallback`, 3d4ee38)
|
||||||
> została **porzucona** — do mastera weszła równoległa, szersza implementacja tego samego
|
> została **porzucona** — do mastera weszła równoległa, szersza implementacja tego samego
|
||||||
> kroku planu (e7625cd, `app/embed_router.py`, 2026-07-29) i to ona biega na PIHA. Ten log
|
> kroku planu (e7625cd, `app/embed_router.py`, 2026-07-29) i to ona biega na PIHA. Ten log
|
||||||
|
|
@ -23,7 +23,7 @@ links: []
|
||||||
> Z delty brancha uratowano ponadto: `retrieval_eval.py --transport http` (plan §2 D6/§9)
|
> Z delty brancha uratowano ponadto: `retrieval_eval.py --transport http` (plan §2 D6/§9)
|
||||||
> i luki testowe T1/T2 przeniesione do `test_embed_router.py`.
|
> i luki testowe T1/T2 przeniesione do `test_embed_router.py`.
|
||||||
|
|
||||||
**Zakres**: `docs/kb/modules/05-faza4-plan.md` §2 decyzja 2 / §5 — aktywny fallback
|
**Zakres**: `kb/phases/kb-m5-faza4.md` §2 decyzja 2 / §5 — aktywny fallback
|
||||||
embedu, ostatni brakujący element rdzenia fazy 4 (frontend i ingress LIVE od
|
embedu, ostatni brakujący element rdzenia fazy 4 (frontend i ingress LIVE od
|
||||||
2026-07-22/23, `docs/sessions/2026-07-23-kb-f4-ingress.md`). Zero zmian w schemacie
|
2026-07-22/23, `docs/sessions/2026-07-23-kb-f4-ingress.md`). Zero zmian w schemacie
|
||||||
DB, zero zmian w `kb_retrieval`'s retrieval logice — wyłącznie warstwa embed + health.
|
DB, zero zmian w `kb_retrieval`'s retrieval logice — wyłącznie warstwa embed + health.
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ e8aa3e3 docs(architecture): recon multiagent 2026-07-27
|
||||||
|
|
||||||
### Files changed
|
### Files changed
|
||||||
```
|
```
|
||||||
docs/architecture/PLAN-subsystem-a-2026-07-28.md | 60 +++
|
kb/phases/subsystem-a-naprawa.md | 60 +++
|
||||||
docs/architecture/RECON-multiagent-2026-07-27.md | 551 +++++++++++++++++++++++
|
kb/subsystems/recon-multiagent.md | 551 +++++++++++++++++++++++
|
||||||
2 files changed, 611 insertions(+)
|
2 files changed, 611 insertions(+)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,12 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: session-log
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-04
|
||||||
|
links: []
|
||||||
|
---
|
||||||
|
|
||||||
# Session log 2026-07-31 — KB Faza 4: zamknięcie + pilot narty27
|
# Session log 2026-07-31 — KB Faza 4: zamknięcie + pilot narty27
|
||||||
|
|
||||||
## Zakres
|
## Zakres
|
||||||
|
|
@ -13,7 +22,7 @@ pilota fazy 5 (narty27), wykonanego równolegle.
|
||||||
- session log 27.07
|
- session log 27.07
|
||||||
- testy luk T1–T3
|
- testy luk T1–T3
|
||||||
- komentarz kalibracji progów dist.
|
- komentarz kalibracji progów dist.
|
||||||
- Pełny rozbiór obu implementacji: `docs/kb/modules/05-fallback-dedup-raport.md`.
|
- Pełny rozbiór obu implementacji: `kb/phases/kb-m5-faza4-fallback-dedup.md`.
|
||||||
|
|
||||||
### Deploy na PIHA (z mastera)
|
### Deploy na PIHA (z mastera)
|
||||||
- `ollama-piha`: named volume `ollama_piha_models`, model bge-m3, `KEEP_ALIVE=0`.
|
- `ollama-piha`: named volume `ollama_piha_models`, model bge-m3, `KEEP_ALIVE=0`.
|
||||||
|
|
@ -67,7 +76,7 @@ infry**. Infra: `services/narty27`.
|
||||||
stubie nie przechodzi wyłącznie z tego powodu.
|
stubie nie przechodzi wyłącznie z tego powodu.
|
||||||
2. **`hosts/solaria/runtime/ollama/docker-compose.override.yml` — brak w repo**
|
2. **`hosts/solaria/runtime/ollama/docker-compose.override.yml` — brak w repo**
|
||||||
(rozjazd repo↔runtime na SOLARII).
|
(rozjazd repo↔runtime na SOLARII).
|
||||||
3. **R1–R3 node-agent** (incydent `docs/incidents/2026-07-30-ollama-solaria-vanish.md`)
|
3. **R1–R3 node-agent** (incydent `kb/incidents/2026-07-30-ollama-solaria-vanish.md`)
|
||||||
— **niezrobione**: R1 `_prune_stopped_containers` nie może kasować kontenerów
|
— **niezrobione**: R1 `_prune_stopped_containers` nie może kasować kontenerów
|
||||||
zarządzanych, R2 rate-limit dla `ai_node`/`standard`, R3 logowanie usuniętych
|
zarządzanych, R2 rate-limit dla `ai_node`/`standard`, R3 logowanie usuniętych
|
||||||
zasobów. Przyczyna nadal aktywna → blokuje/warunkuje fazę mailową
|
zasobów. Przyczyna nadal aktywna → blokuje/warunkuje fazę mailową
|
||||||
|
|
|
||||||
5
hosts/chelsty-infra/README.md
Normal file
5
hosts/chelsty-infra/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# CHELSTY-INFRA
|
||||||
|
|
||||||
|
Runtime environment and deployment flow for CHELSTY, an offline-capable home automation edge node split across two VMs.
|
||||||
|
|
||||||
|
Dokumentacja: [kb/nodes/chelsty-infra.md](../../kb/nodes/chelsty-infra.md)
|
||||||
5
hosts/piha/README.md
Normal file
5
hosts/piha/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# PIHA
|
||||||
|
|
||||||
|
Infrastructure + Automation Node.
|
||||||
|
|
||||||
|
Dokumentacja: [kb/nodes/piha.md](../../kb/nodes/piha.md)
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# PIHA-specific override for node_exporter.
|
# PIHA-specific override for node_exporter.
|
||||||
#
|
#
|
||||||
# WHY: KB module 5 phase 3 step 5 (docs/kb/modules/05-faza3-plan.md §7.2) needs the
|
# WHY: KB module 5 phase 3 step 5 (kb/phases/kb-m5-faza3.md §7.2) needs the
|
||||||
# textfile collector so kb-ingest's systemd timer can publish
|
# textfile collector so kb-ingest's systemd timer can publish
|
||||||
# kb_ingest_last_success_timestamp / kb_ingest_last_exit_code / kb_ingest_embed_backlog
|
# kb_ingest_last_success_timestamp / kb_ingest_last_exit_code / kb_ingest_embed_backlog
|
||||||
# etc. for fleet-prometheus to scrape and alert on.
|
# etc. for fleet-prometheus to scrape and alert on.
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ services:
|
||||||
external: []
|
external: []
|
||||||
runtime:
|
runtime:
|
||||||
# textfile collector reads /opt/homelab/state/node-exporter (module 5 phase 3 step 5,
|
# textfile collector reads /opt/homelab/state/node-exporter (module 5 phase 3 step 5,
|
||||||
# docs/kb/modules/05-faza3-plan.md §7.2 — kb-ingest.prom) via the existing /:/host:ro
|
# kb/phases/kb-m5-faza3.md §7.2 — kb-ingest.prom) via the existing /:/host:ro
|
||||||
# mount, see hosts/piha/runtime/node_exporter/docker-compose.override.yml.
|
# mount, see hosts/piha/runtime/node_exporter/docker-compose.override.yml.
|
||||||
data_path: /opt/homelab/state/node-exporter
|
data_path: /opt/homelab/state/node-exporter
|
||||||
|
|
||||||
|
|
@ -161,7 +161,7 @@ services:
|
||||||
runtime:
|
runtime:
|
||||||
# No config and no secrets. Content is PERSONAL and deliberately outside
|
# No config and no secrets. Content is PERSONAL and deliberately outside
|
||||||
# the repo — it lives only in the Docker named volume
|
# the repo — it lives only in the Docker named volume
|
||||||
# narty27_narty27_content, refreshed from SOLARIA (services/narty27/README.md).
|
# narty27_narty27_content, refreshed from SOLARIA (kb/runbooks/narty27-deploy.md).
|
||||||
# No backup job, no /opt/homelab/data bind.
|
# No backup job, no /opt/homelab/data bind.
|
||||||
config_path: services/narty27
|
config_path: services/narty27
|
||||||
|
|
||||||
|
|
|
||||||
5
hosts/saturn/README.md
Normal file
5
hosts/saturn/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# SATURN
|
||||||
|
|
||||||
|
Primary Development & Orchestration Node.
|
||||||
|
|
||||||
|
Dokumentacja: [kb/nodes/saturn.md](../../kb/nodes/saturn.md)
|
||||||
5
hosts/solaria/README.md
Normal file
5
hosts/solaria/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# SOLARIA
|
||||||
|
|
||||||
|
Compute / GPU / Inference Node.
|
||||||
|
|
||||||
|
Dokumentacja: [kb/nodes/solaria.md](../../kb/nodes/solaria.md)
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# MITYGACJA TYMCZASOWA (M1) — założona 2026-08-04.
|
# MITYGACJA TYMCZASOWA (M1) — założona 2026-08-04.
|
||||||
# NODE_TYPE=lte_node wyłącza run_safe_cleanup() (niefiltrowany
|
# NODE_TYPE=lte_node wyłącza run_safe_cleanup() (niefiltrowany
|
||||||
# `docker container prune`) na czas backfillu embed (faza mailowa KB).
|
# `docker container prune`) na czas backfillu embed (faza mailowa KB).
|
||||||
# Incydent: docs/incidents/2026-07-30-ollama-solaria-vanish.md (§7, M1).
|
# Incydent: kb/incidents/2026-07-30-ollama-solaria-vanish.md (§7, M1).
|
||||||
# Bez tego każdy zatrzymany kontener na SOLARII znika w ≤60 s — również taki
|
# Bez tego każdy zatrzymany kontener na SOLARII znika w ≤60 s — również taki
|
||||||
# z `restart: unless-stopped`, zatrzymany świadomie przez operatora.
|
# z `restart: unless-stopped`, zatrzymany świadomie przez operatora.
|
||||||
# Warunek zdjęcia: R1 (filtrowanie prune po restart policy / labelu compose)
|
# Warunek zdjęcia: R1 (filtrowanie prune po restart policy / labelu compose)
|
||||||
|
|
|
||||||
5
hosts/vps/README.md
Normal file
5
hosts/vps/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# VPS
|
||||||
|
|
||||||
|
Public Edge + Ingress Node.
|
||||||
|
|
||||||
|
Dokumentacja: [kb/nodes/vps.md](../../kb/nodes/vps.md)
|
||||||
|
|
@ -167,5 +167,5 @@ services:
|
||||||
# redis, mosquitto): legacy stack, runs UNMANAGED on vps and is scheduled
|
# redis, mosquitto): legacy stack, runs UNMANAGED on vps and is scheduled
|
||||||
# for retirement — its codex/* bus has been idle since 2026-06-09.
|
# for retirement — its codex/* bus has been idle since 2026-06-09.
|
||||||
# Deliberately NO entry here: legacy is not pulled into desired state.
|
# Deliberately NO entry here: legacy is not pulled into desired state.
|
||||||
# See docs/architecture/ai-cluster-LEGACY.md and
|
# See kb/decisions/ai-cluster-legacy.md and
|
||||||
# docs/architecture/RECON-multiagent-2026-07-27.md (C9).
|
# kb/subsystems/recon-multiagent.md (C9).
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# jobs/deploy-runner/deploy-runner.sh — host-side executor for `redeploy` actions.
|
# jobs/deploy-runner/deploy-runner.sh — host-side executor for `redeploy` actions.
|
||||||
#
|
#
|
||||||
# WHY THIS EXISTS (docs/architecture/RECON-multiagent-2026-07-27.md D14/D15):
|
# WHY THIS EXISTS (kb/subsystems/recon-multiagent.md D14/D15):
|
||||||
# the control-plane executor could never carry out a redeploy — it ran
|
# the control-plane executor could never carry out a redeploy — it ran
|
||||||
# deploy-node.sh inside its own container, a script that ignores its arguments
|
# deploy-node.sh inside its own container, a script that ignores its arguments
|
||||||
# and expects a repo at ${HOME}/homelab-codex-ws that does not exist there (nor
|
# and expects a repo at ${HOME}/homelab-codex-ws that does not exist there (nor
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
# dead-ended, which is the single biggest reason the self-healing loop had
|
# dead-ended, which is the single biggest reason the self-healing loop had
|
||||||
# 18 pending / 0 completed actions.
|
# 18 pending / 0 completed actions.
|
||||||
#
|
#
|
||||||
# The fix keeps the architecture decision from docs/backlog.md ("Remediacja
|
# The fix keeps the architecture decision from kb/phases/backlog.md ("Remediacja
|
||||||
# floty bez SSH"): the VPS never initiates a connection to a node. The executor
|
# floty bez SSH"): the VPS never initiates a connection to a node. The executor
|
||||||
# only WRITES an action file; this runner, on the target node, pulls it, runs
|
# only WRITES an action file; this runner, on the target node, pulls it, runs
|
||||||
# the deploy locally, and reports the outcome back through the existing event
|
# the deploy locally, and reports the outcome back through the existing event
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Eval-set for the retrieval quality gate (module 5, phase 3, plan §6.2,
|
# Eval-set for the retrieval quality gate (module 5, phase 3, plan §6.2,
|
||||||
# docs/kb/modules/05-faza3-plan.md). Transcribed 1:1 from the pilot baseline,
|
# kb/phases/kb-m5-faza3.md). Transcribed 1:1 from the pilot baseline,
|
||||||
# docs/kb/eval/retrieval-pilot-2026-07-16.md (read-only source -- this file is the versioned
|
# kb/phases/kb-m5-eval-retrieval-pilot.md (read-only source -- this file is the versioned
|
||||||
# copy the plan asked for, so the set stops living only in a session transcript).
|
# copy the plan asked for, so the set stops living only in a session transcript).
|
||||||
#
|
#
|
||||||
# kind:
|
# kind:
|
||||||
|
|
@ -80,7 +80,7 @@ queries:
|
||||||
wpis, patrz historia sesji). Próg tej kontroli obniżony do 0.50 (z 0.55) właśnie z powodu
|
wpis, patrz historia sesji). Próg tej kontroli obniżony do 0.50 (z 0.55) właśnie z powodu
|
||||||
tej znanej kolizji, żeby bramka nie płonęła co uruchomienie na nie-problemie.
|
tej znanej kolizji, żeby bramka nie płonęła co uruchomienie na nie-problemie.
|
||||||
|
|
||||||
# Faza mailowa (docs/kb/modules/05-faza-mailowa-plan.md, §8, Krok 5) -- bramka jakościowa dla
|
# Faza mailowa (kb/phases/kb-m5-faza-mailowa.md, §8, Krok 5) -- bramka jakościowa dla
|
||||||
# treści mailowej wprowadzonej w Etapie A (ostatnie 12 miesięcy, plan §7 Krok 4). Wypełniona
|
# treści mailowej wprowadzonej w Etapie A (ostatnie 12 miesięcy, plan §7 Krok 4). Wypełniona
|
||||||
# przez operatora 2026-07-23 (5 zapytań "wiem że to mam w mailach z ostatniego roku"; M5
|
# przez operatora 2026-07-23 (5 zapytań "wiem że to mam w mailach z ostatniego roku"; M5
|
||||||
# odrzucone po weryfikacji, patrz N2 powyżej i historia sesji). expected_envelope celowo null
|
# odrzucone po weryfikacji, patrz N2 powyżej i historia sesji). expected_envelope celowo null
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
"""Retrieval quality gate -- module 5, phase 3, plan §6.2 (docs/kb/modules/05-faza3-plan.md),
|
"""Retrieval quality gate -- module 5, phase 3, plan §6.2 (kb/phases/kb-m5-faza3.md),
|
||||||
extended in faza mailowa Krok 5 (docs/kb/modules/05-faza-mailowa-plan.md, §8) to add the
|
extended in faza mailowa Krok 5 (kb/phases/kb-m5-faza-mailowa.md, §8) to add the
|
||||||
`hybrid` track once mail content exists in `document_chunk` (faza mailowa Krok 2/4).
|
`hybrid` track once mail content exists in `document_chunk` (faza mailowa Krok 2/4).
|
||||||
|
|
||||||
Read-only integration script (NOT collected by pytest -- it hits the live kb-postgres DB and
|
Read-only integration script (NOT collected by pytest -- it hits the live kb-postgres DB and
|
||||||
|
|
@ -343,7 +343,7 @@ def print_report(
|
||||||
rows: list[dict], n_values: list[int], gate_result: dict, mail_rows: Optional[list[dict]] = None
|
rows: list[dict], n_values: list[int], gate_result: dict, mail_rows: Optional[list[dict]] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
print("=" * 100)
|
print("=" * 100)
|
||||||
print("RETRIEVAL QUALITY GATE -- plan §6.2 (docs/kb/modules/05-faza3-plan.md), "
|
print("RETRIEVAL QUALITY GATE -- plan §6.2 (kb/phases/kb-m5-faza3.md), "
|
||||||
"+ hybrid/mail extension (05-faza-mailowa-plan.md §8)")
|
"+ hybrid/mail extension (05-faza-mailowa-plan.md §8)")
|
||||||
print("=" * 100)
|
print("=" * 100)
|
||||||
header = f"{'id':<3} {'kind':<28} {'expected':<16} {'flat d1':>8} {'flat@3':>7}"
|
header = f"{'id':<3} {'kind':<28} {'expected':<16} {'flat d1':>8} {'flat@3':>7}"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
"""Chunk + embed job — module 5 phase 2, plan step 6 (docs/kb/modules/05-faza2-plan.md,
|
"""Chunk + embed job — module 5 phase 2, plan step 6 (kb/phases/kb-m5-faza2.md,
|
||||||
§6 step 6, decision 3).
|
§6 step 6, decision 3).
|
||||||
|
|
||||||
`chunk_text`/`hard_split`/`split_paragraphs`/`TARGET_CHARS`/`OVERLAP_CHARS` moved to
|
`chunk_text`/`hard_split`/`split_paragraphs`/`TARGET_CHARS`/`OVERLAP_CHARS` moved to
|
||||||
`kb_mail.chunking` in module 5 faza mailowa, Krok 0 (docs/kb/modules/05-faza-mailowa-plan.md, §3)
|
`kb_mail.chunking` in module 5 faza mailowa, Krok 0 (kb/phases/kb-m5-faza-mailowa.md, §3)
|
||||||
so `jobs/mail-body-ingest` shares the exact same chunker instead of a copy-pasted drift; re-exported
|
so `jobs/mail-body-ingest` shares the exact same chunker instead of a copy-pasted drift; re-exported
|
||||||
here unchanged so nothing importing them from this module breaks.
|
here unchanged so nothing importing them from this module breaks.
|
||||||
|
|
||||||
|
|
@ -23,7 +23,7 @@ Install (from repo root):
|
||||||
pip install -e jobs/documents-ingest/
|
pip install -e jobs/documents-ingest/
|
||||||
|
|
||||||
`embed_chunk`/`_vector_literal`/`DEFAULT_MODEL`/`DEFAULT_OLLAMA_URL` moved to
|
`embed_chunk`/`_vector_literal`/`DEFAULT_MODEL`/`DEFAULT_OLLAMA_URL` moved to
|
||||||
`kb_retrieval.embed` in module 5 phase 4 (docs/kb/modules/05-faza4-plan.md, §3, decision 1) so
|
`kb_retrieval.embed` in module 5 phase 4 (kb/phases/kb-m5-faza4.md, §3, decision 1) so
|
||||||
`kb-query` (Docker service) can share the same client without pulling in this job's `anthropic`
|
`kb-query` (Docker service) can share the same client without pulling in this job's `anthropic`
|
||||||
dependency; re-exported here unchanged so nothing importing them from this module breaks.
|
dependency; re-exported here unchanged so nothing importing them from this module breaks.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Cyclic ingest wrapper -- module 5 phase 3, plan step 5 (docs/kb/modules/05-faza3-plan.md,
|
"""Cyclic ingest wrapper -- module 5 phase 3, plan step 5 (kb/phases/kb-m5-faza3.md,
|
||||||
§7). Orchestrates one run of the recurring ingest pipeline for `kb-ingest.timer` on PIHA:
|
§7). Orchestrates one run of the recurring ingest pipeline for `kb-ingest.timer` on PIHA:
|
||||||
|
|
||||||
paperless_adapter.run() -- new source='paperless' envelopes
|
paperless_adapter.run() -- new source='paperless' envelopes
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"""PDF attachment extractor — kb-postgres mail archive -> Paperless consume/.
|
"""PDF attachment extractor — kb-postgres mail archive -> Paperless consume/.
|
||||||
|
|
||||||
Module 5 ("documents-ingest"), Phase 1 (docs/kb/modules/05-documents-ingest.md,
|
Module 5 ("documents-ingest"), Phase 1 (kb/phases/kb-m5-documents-ingest.md,
|
||||||
section "Domkniecie dlugu z maili"): pull a sample of PDF attachments out of the
|
section "Domkniecie dlugu z maili"): pull a sample of PDF attachments out of the
|
||||||
Gmail .eml archive and drop them into Paperless' consume/ dir so Paperless does
|
Gmail .eml archive and drop them into Paperless' consume/ dir so Paperless does
|
||||||
the OCR + correspondent-detection. This is NOT the Paperless/Nextcloud envelope
|
the OCR + correspondent-detection. This is NOT the Paperless/Nextcloud envelope
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Paperless -> envelope adapter — module 5 phase 2 (docs/kb/modules/05-faza2-plan.md,
|
"""Paperless -> envelope adapter — module 5 phase 2 (kb/phases/kb-m5-faza2.md,
|
||||||
§4.2-4.3, §6 step 5).
|
§4.2-4.3, §6 step 5).
|
||||||
|
|
||||||
Reads documents from the Paperless REST API (read-only — GET only, this job never
|
Reads documents from the Paperless REST API (read-only — GET only, this job never
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
"""Re-export shim -- the retrieval module moved to `packages/kb-retrieval/` in module 5 phase
|
"""Re-export shim -- the retrieval module moved to `packages/kb-retrieval/` in module 5 phase
|
||||||
4 (docs/kb/modules/05-faza4-plan.md, §3, decision 1) so both this job and `kb-query` (Docker
|
4 (kb/phases/kb-m5-faza4.md, §3, decision 1) so both this job and `kb-query` (Docker
|
||||||
service) share one tested module. Kept here unchanged so nothing importing
|
service) share one tested module. Kept here unchanged so nothing importing
|
||||||
`documents_ingest.retrieval` breaks; new code should import `kb_retrieval.retrieval` directly.
|
`documents_ingest.retrieval` breaks; new code should import `kb_retrieval.retrieval` directly.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Summarize + tag job — module 5 phase 3, plan step 3 (docs/kb/modules/05-faza3-plan.md,
|
"""Summarize + tag job — module 5 phase 3, plan step 3 (kb/phases/kb-m5-faza3.md,
|
||||||
§5 step 3, §2 decision 3: two-track A/B pilot).
|
§5 step 3, §2 decision 3: two-track A/B pilot).
|
||||||
|
|
||||||
Pipeline: `document_chunk.text WHERE excluded_reason IS NULL ORDER BY chunk_index` per
|
Pipeline: `document_chunk.text WHERE excluded_reason IS NULL ORDER BY chunk_index` per
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# kb-ingest-run.sh — thin launcher for kb-ingest.service (module 5 phase 3 step 5,
|
# kb-ingest-run.sh — thin launcher for kb-ingest.service (module 5 phase 3 step 5,
|
||||||
# docs/kb/modules/05-faza3-plan.md §7.1).
|
# kb/phases/kb-m5-faza3.md §7.1).
|
||||||
#
|
#
|
||||||
# All sequencing/tolerance/exit-code logic lives in documents-ingest-cyclic (Python,
|
# All sequencing/tolerance/exit-code logic lives in documents-ingest-cyclic (Python,
|
||||||
# jobs/documents-ingest/src/documents_ingest/cyclic_ingest.py) — this script only computes
|
# jobs/documents-ingest/src/documents_ingest/cyclic_ingest.py) — this script only computes
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ class TestVectorLiteral:
|
||||||
|
|
||||||
|
|
||||||
class TestIsOcrJunk:
|
class TestIsOcrJunk:
|
||||||
"""Pilot cases from docs/kb/modules/05-faza3-plan.md §3.1 and the 2026-07-16 calibration
|
"""Pilot cases from kb/phases/kb-m5-faza3.md §3.1 and the 2026-07-16 calibration
|
||||||
session (docs/kb/eval/retrieval-pilot-2026-07-16.md)."""
|
session (kb/phases/kb-m5-eval-retrieval-pilot.md)."""
|
||||||
|
|
||||||
def test_clean_text_is_not_junk(self):
|
def test_clean_text_is_not_junk(self):
|
||||||
text = (
|
text = (
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Gmail header backfill — one-shot job, module 5 phase 2 (docs/kb/modules/05-faza2-plan.md, §5).
|
"""Gmail header backfill — one-shot job, module 5 phase 2 (kb/phases/kb-m5-faza2.md, §5).
|
||||||
|
|
||||||
Backfills `{"type": "headers", ...}` (§4.1) onto the 225 030 existing `source='gmail'`
|
Backfills `{"type": "headers", ...}` (§4.1) onto the 225 030 existing `source='gmail'`
|
||||||
envelope rows in kb-postgres, which today carry only an attachment manifest. This is an
|
envelope rows in kb-postgres, which today carry only an attachment manifest. This is an
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
"""Mail body ingest job — module 5, faza mailowa, plan Krok 2
|
"""Mail body ingest job — module 5, faza mailowa, plan Krok 2
|
||||||
(docs/kb/modules/05-faza-mailowa-plan.md, §5). Second full pass over the gmail .eml archive
|
(kb/phases/kb-m5-faza-mailowa.md, §5). Second full pass over the gmail .eml archive
|
||||||
(the first was gmail-bulk-import's manifest-only import): extracts inline body text that
|
(the first was gmail-bulk-import's manifest-only import): extracts inline body text that
|
||||||
`_parse_attachments` deliberately skipped, chunks it, embeds it (batched), and appends
|
`_parse_attachments` deliberately skipped, chunks it, embeds it (batched), and appends
|
||||||
`entities[type=threading]` — the only new writes are `document_chunk` INSERTs and an additive
|
`entities[type=threading]` — the only new writes are `document_chunk` INSERTs and an additive
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: audit
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-07-30
|
||||||
|
as_of: 2026-07-30
|
||||||
|
links: []
|
||||||
|
---
|
||||||
|
|
||||||
# Recon — node-agent vs stability-agent (2026-07-30)
|
# Recon — node-agent vs stability-agent (2026-07-30)
|
||||||
|
|
||||||
Read-only recon. Ground truth: `docs/architecture/RECON-multiagent-2026-07-27.md`
|
Read-only recon. Ground truth: `kb/subsystems/recon-multiagent.md`
|
||||||
(A1, A2, B7, D15). Source read at master @ `473bf8e`; this branch is cut from
|
(A1, A2, B7, D15). Source read at master @ `473bf8e`; this branch is cut from
|
||||||
master @ `0650eb8`. The two intervening merges (`0650eb8` ha-mcp, `cb8a19d`
|
master @ `0650eb8`. The two intervening merges (`0650eb8` ha-mcp, `cb8a19d`
|
||||||
kb-query tests) touch none of the audited paths — `services/node-agent/`,
|
kb-query tests) touch none of the audited paths — `services/node-agent/`,
|
||||||
|
|
@ -56,7 +66,7 @@ control plane, stability-agent feeds the agent-system UI, and stability-agent's
|
||||||
half of the event store is a write-only archive nothing has ever read.
|
half of the event store is a write-only archive nothing has ever read.
|
||||||
|
|
||||||
A prior recon reached the same conclusion about the event path on 2026-07-06
|
A prior recon reached the same conclusion about the event path on 2026-07-06
|
||||||
(`docs/infra/prometheus-cutover-recon-2026-07-06.md:88-91`); it has not been acted on.
|
(`kb/audits/prometheus-cutover-2026-07-06.md:88-91`); it has not been acted on.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -297,7 +307,7 @@ prefix that `container_service_name()` was written to strip.
|
||||||
- Remove entries from `hosts/solaria/services.yaml` and `hosts/vps/services.yaml`.
|
- Remove entries from `hosts/solaria/services.yaml` and `hosts/vps/services.yaml`.
|
||||||
- `docker compose down` on vps, piha, solaria (chelsty-infra when reachable).
|
- `docker compose down` on vps, piha, solaria (chelsty-infra when reachable).
|
||||||
- Purge or archive `/opt/homelab/events/2026-*/` on all four nodes (~5 MB on piha, mostly May).
|
- Purge or archive `/opt/homelab/events/2026-*/` on all four nodes (~5 MB on piha, mostly May).
|
||||||
- Update CLAUDE.md (agent-system architecture §1, event-path claim at line 100), `docs/chelsty-stability-agent.md`, recon A1/A2/B7.
|
- Update CLAUDE.md (agent-system architecture §1, event-path claim at line 100), `kb/services/chelsty-stability-agent.md`, recon A1/A2/B7.
|
||||||
- **Not covered by the cleanup:** the Redis publisher must be rehomed first or the UI loss is permanent.
|
- **Not covered by the cleanup:** the Redis publisher must be rehomed first or the UI loss is permanent.
|
||||||
|
|
||||||
### (b) Merge stability-agent's unique checks into node-agent
|
### (b) Merge stability-agent's unique checks into node-agent
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: audit
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-07-16
|
||||||
|
as_of: 2026-07-16
|
||||||
|
links: []
|
||||||
|
---
|
||||||
|
|
||||||
# Recon: lustro `event=dead prom=up` — 1507 mismatchy w shadow-liveness.log (2026-07-16)
|
# Recon: lustro `event=dead prom=up` — 1507 mismatchy w shadow-liveness.log (2026-07-16)
|
||||||
|
|
||||||
READ-ONLY recon. Zero zmian w kodzie/serwisach. Wszystkie czasy **UTC**
|
READ-ONLY recon. Zero zmian w kodzie/serwisach. Wszystkie czasy **UTC**
|
||||||
|
|
@ -131,7 +131,7 @@ compose-service kontenera.
|
||||||
| owntracks-prometheus-exporter-prometheus-owntracks-exporter-1 | linusgroh/prometheus-owntracks-exporter | Up 2w | 0.0.0.0:8780→80 |
|
| owntracks-prometheus-exporter-prometheus-owntracks-exporter-1 | linusgroh/prometheus-owntracks-exporter | Up 2w | 0.0.0.0:8780→80 |
|
||||||
| own-tracks-frontend-owntracks-frontend-1 | owntracks/frontend | Up 2w | 0.0.0.0:8084→80 |
|
| own-tracks-frontend-owntracks-frontend-1 | owntracks/frontend | Up 2w | 0.0.0.0:8084→80 |
|
||||||
|
|
||||||
Zmiany vs audyt 2026-06-30 (`docs/infra/inventory-2026-06-30.md`): **przybyły** paperless,
|
Zmiany vs audyt 2026-06-30 (`kb/subsystems/fleet-inventory.md`): **przybyły** paperless,
|
||||||
paperless-db, paperless-broker (Deploy 1, 2026-07-10); **zniknęły** diskover i elasticsearch
|
paperless-db, paperless-broker (Deploy 1, 2026-07-10); **zniknęły** diskover i elasticsearch
|
||||||
(w audycie 06-30 były w 33 shadow; dziś nie biegają). 06-30: 40 kontenerów → dziś: 42.
|
(w audycie 06-30 były w 33 shadow; dziś nie biegają). 06-30: 40 kontenerów → dziś: 42.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: audit
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-07-02
|
||||||
|
as_of: 2026-07-02
|
||||||
|
links: []
|
||||||
|
---
|
||||||
|
|
||||||
# Audyt odchudzania PIHA — 2026-07-02
|
# Audyt odchudzania PIHA — 2026-07-02
|
||||||
|
|
||||||
> Faza 1 (READ-ONLY) modulu 0 filaru dokumentow (`docs/kb/modules/00-piha-slim.md`).
|
> Faza 1 (READ-ONLY) modulu 0 filaru dokumentow (`kb/phases/kb-m0-piha-slim.md`).
|
||||||
> Zadna akcja nie zostala wykonana — wylacznie `docker stats/inspect/logs`, `ss`, `curl` (odczyt).
|
> Zadna akcja nie zostala wykonana — wylacznie `docker stats/inspect/logs`, `ss`, `curl` (odczyt).
|
||||||
> Stan w momencie audytu: **RAM 7.9Gi total, 5.0Gi used, 2.9Gi available; swap 4Gi total, 2.0Gi uzyty.**
|
> Stan w momencie audytu: **RAM 7.9Gi total, 5.0Gi used, 2.9Gi available; swap 4Gi total, 2.0Gi uzyty.**
|
||||||
> 41 kontenerow Up (inwentaryzacja 2026-06-30 liczyla 40; wszystkie nadal biega).
|
> 41 kontenerow Up (inwentaryzacja 2026-06-30 liczyla 40; wszystkie nadal biega).
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: audit
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-07-06
|
||||||
|
as_of: 2026-07-06
|
||||||
|
links: []
|
||||||
|
---
|
||||||
|
|
||||||
# Prometheus liveness cutover — recon starego toru (2026-07-06)
|
# Prometheus liveness cutover — recon starego toru (2026-07-06)
|
||||||
|
|
||||||
Read-only recon przed cutoverem liveności floty na Prometheus `up{}`. Mapa obecnego
|
Read-only recon przed cutoverem liveności floty na Prometheus `up{}`. Mapa obecnego
|
||||||
|
|
@ -290,7 +300,7 @@ renderuje `health`/`status`/`last_seen`), `/unhealthy` (`:302-334`), `/summary`,
|
||||||
chelsty/chelsty-infra (exporter DOWN po LTE, 2026-06-26).
|
chelsty/chelsty-infra (exporter DOWN po LTE, 2026-06-26).
|
||||||
- Reguła `NodeDown` (`rules/liveness.yml:21-28`): `up{node=~"vps|piha"} == 0`,
|
- Reguła `NodeDown` (`rules/liveness.yml:21-28`): `up{node=~"vps|piha"} == 0`,
|
||||||
`for: 5m`, severity critical. solaria/lustro świadomie wykluczone (`:12-16` —
|
`for: 5m`, severity critical. solaria/lustro świadomie wykluczone (`:12-16` —
|
||||||
planned power-off; docelowo anomaly detection, `docs/backlog.md:390-406`).
|
planned power-off; docelowo anomaly detection, `kb/phases/backlog.md:390-406`).
|
||||||
Bez Alertmanagera by design (`:3-7`) — delivery = brain-watchdog poll `/api/v1/alerts`.
|
Bez Alertmanagera by design (`:3-7`) — delivery = brain-watchdog poll `/api/v1/alerts`.
|
||||||
- node_exporter w repo tylko dla VPS (`services/node_exporter/`, network_mode: host,
|
- node_exporter w repo tylko dla VPS (`services/node_exporter/`, network_mode: host,
|
||||||
`hosts/vps/services.yaml:36-43`). Exportery na piha/solaria/lustro **nie mają
|
`hosts/vps/services.yaml:36-43`). Exportery na piha/solaria/lustro **nie mają
|
||||||
|
|
@ -338,7 +348,7 @@ chelsty-infra, chelsty-ha, lustro.
|
||||||
| lustro | TAK (`:50-52`) | NIE | TAK (bez stability-agenta) | jw. |
|
| lustro | TAK (`:50-52`) | NIE | TAK (bez stability-agenta) | jw. |
|
||||||
| **chelsty-infra** | **NIE** (`:57-60`, exporter DOWN po LTE) | NIE | **TAK** (remote TTL 900/3600, `liveness.py:43-50`) | **tylko stary tor — cutover totalny zostawiłby go bez liveności** |
|
| **chelsty-infra** | **NIE** (`:57-60`, exporter DOWN po LTE) | NIE | **TAK** (remote TTL 900/3600, `liveness.py:43-50`) | **tylko stary tor — cutover totalny zostawiłby go bez liveności** |
|
||||||
| chelsty-ha | NIE | NIE | NIE (`hosts/chelsty-ha/services.yaml:6-12`, `monitor: false`) | już dziś bez liveności (pośrednio przez MQTT chelsty-infra) — cutover nic nie zmienia |
|
| chelsty-ha | NIE | NIE | NIE (`hosts/chelsty-ha/services.yaml:6-12`, `monitor: false`) | już dziś bez liveności (pośrednio przez MQTT chelsty-infra) — cutover nic nie zmienia |
|
||||||
| saturn | NIE (`:55`, laptop) | NIE | NIE (brak `hosts/saturn/services.yaml`, `docs/backlog.md:423`) | już dziś bez liveności — cutover nic nie zmienia |
|
| saturn | NIE (`:55`, laptop) | NIE | NIE (brak `hosts/saturn/services.yaml`, `kb/phases/backlog.md:423`) | już dziś bez liveności — cutover nic nie zmienia |
|
||||||
|
|
||||||
**Chelsty offline ~34 dni — jak traktuje go stara rura:** eventy buforują się lokalnie
|
**Chelsty offline ~34 dni — jak traktuje go stara rura:** eventy buforują się lokalnie
|
||||||
(rsync fail = non-fatal, `node_agent.py:560-566`), `last_seen` na VPS zamrożone sprzed
|
(rsync fail = non-fatal, `node_agent.py:560-566`), `last_seen` na VPS zamrożone sprzed
|
||||||
|
|
@ -351,7 +361,7 @@ totalnym chelsty-infra nie miałby żadnej liveności i żadnego przejścia offl
|
||||||
Dodatkowo docs sygnalizują konflikt IP w komentarzach `prometheus.yml:57` vs
|
Dodatkowo docs sygnalizują konflikt IP w komentarzach `prometheus.yml:57` vs
|
||||||
`hosts/chelsty-infra/host.yaml:12` — do wyjaśnienia przy ewentualnym dodawaniu scrape.
|
`hosts/chelsty-infra/host.yaml:12` — do wyjaśnienia przy ewentualnym dodawaniu scrape.
|
||||||
*(rzeczywisty bieżący stan chelsty — do weryfikacji na żywo; ostatni zapis:
|
*(rzeczywisty bieżący stan chelsty — do weryfikacji na żywo; ostatni zapis:
|
||||||
UNREACHABLE, `docs/infra/inventory-verify-2026-07-02.md:17,151`)*
|
UNREACHABLE, `kb/subsystems/fleet-inventory-verify.md:17,151`)*
|
||||||
|
|
||||||
**Wniosek twardy:** cutover NIE może być globalny. Docelowa architektura to
|
**Wniosek twardy:** cutover NIE może być globalny. Docelowa architektura to
|
||||||
**hybryda per-node**: `up{}` dla scrape'owanych (vps, piha, solaria, lustro),
|
**hybryda per-node**: `up{}` dla scrape'owanych (vps, piha, solaria, lustro),
|
||||||
|
|
@ -450,7 +460,7 @@ z `last_seen` — rzadszy heartbeat przy niezmienionych TTL-ach = fałszywe degr
|
||||||
- chelsty-infra: zbadać exporter-over-LTE (`prometheus.yml:57-60` + konflikt IP
|
- chelsty-infra: zbadać exporter-over-LTE (`prometheus.yml:57-60` + konflikt IP
|
||||||
z `hosts/chelsty-infra/host.yaml:12`); do tego czasu zostaje na torze eventowym.
|
z `hosts/chelsty-infra/host.yaml:12`); do tego czasu zostaje na torze eventowym.
|
||||||
- NodeDown dla solaria/lustro: świadomie odroczone do anomaly detection
|
- NodeDown dla solaria/lustro: świadomie odroczone do anomaly detection
|
||||||
(`docs/backlog.md:390-406`) — nie wciągać do cutoveru.
|
(`kb/phases/backlog.md:390-406`) — nie wciągać do cutoveru.
|
||||||
- Watchdog na sam Prometheus (D.2 pkt 5) — mały task przy etapie 3.
|
- Watchdog na sam Prometheus (D.2 pkt 5) — mały task przy etapie 3.
|
||||||
- saturn / chelsty-ha: świadomie poza monitoringiem — status quo.
|
- saturn / chelsty-ha: świadomie poza monitoringiem — status quo.
|
||||||
|
|
||||||
|
|
@ -458,7 +468,7 @@ z `last_seen` — rzadszy heartbeat przy niezmienionych TTL-ach = fałszywe degr
|
||||||
|
|
||||||
**Seria.** Minimalnie trzy taski implementacyjne + weryfikacje między nimi:
|
**Seria.** Minimalnie trzy taski implementacyjne + weryfikacje między nimi:
|
||||||
(1) etap 1 shadow-read; (2) etap 3 flaga per-node (po tygodniu etapu 2);
|
(1) etap 1 shadow-read; (2) etap 3 flaga per-node (po tygodniu etapu 2);
|
||||||
(3) watchdog-na-Prometheusa + aktualizacja `docs/observer-runtime.md`.
|
(3) watchdog-na-Prometheusa + aktualizacja `kb/subsystems/observer.md`.
|
||||||
Etap 0 to czynność operatorska (runtime, nie repo). Etap 5 to niezależny backlog.
|
Etap 0 to czynność operatorska (runtime, nie repo). Etap 5 to niezależny backlog.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: audit
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-07-27
|
||||||
|
as_of: 2026-07-27
|
||||||
|
links: []
|
||||||
|
---
|
||||||
|
|
||||||
# Audyt niezarządzanych stacków na VPS — 2026-07-27
|
# Audyt niezarządzanych stacków na VPS — 2026-07-27
|
||||||
|
|
||||||
Recon read-only przed konsolidacją do GitOps. Zebrane przez `ssh vps` (user `oskar`,
|
Recon read-only przed konsolidacją do GitOps. Zebrane przez `ssh vps` (user `oskar`,
|
||||||
|
|
@ -14,7 +14,7 @@ links: []
|
||||||
Stack **ai-cluster** działający na vps (`ai-cluster-openclaw-1`, `codex-worker`,
|
Stack **ai-cluster** działający na vps (`ai-cluster-openclaw-1`, `codex-worker`,
|
||||||
`planner-worker`, `service-ops-worker`, `redis`, `mosquitto`) jest **wygaszany,
|
`planner-worker`, `service-ops-worker`, `redis`, `mosquitto`) jest **wygaszany,
|
||||||
nie migrowany**. Podstawa (recon
|
nie migrowany**. Podstawa (recon
|
||||||
[RECON-multiagent-2026-07-27.md](RECON-multiagent-2026-07-27.md), C9):
|
[RECON-multiagent-2026-07-27.md](../subsystems/recon-multiagent.md), C9):
|
||||||
bus `codex/*` jest martwy od **2026-06-09** — zero nowych połączeń przez ~7 tygodni,
|
bus `codex/*` jest martwy od **2026-06-09** — zero nowych połączeń przez ~7 tygodni,
|
||||||
workery trzymają tylko puste długożyjące połączenia.
|
workery trzymają tylko puste długożyjące połączenia.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ links: []
|
||||||
# Architektura — decyzje obowiązujące
|
# Architektura — decyzje obowiązujące
|
||||||
|
|
||||||
Stan decyzji na 2026-07-28. Podstawa dowodowa:
|
Stan decyzji na 2026-07-28. Podstawa dowodowa:
|
||||||
[RECON-multiagent-2026-07-27.md](RECON-multiagent-2026-07-27.md); plan wykonawczy:
|
[RECON-multiagent-2026-07-27.md](../subsystems/recon-multiagent.md); plan wykonawczy:
|
||||||
[PLAN-subsystem-a-2026-07-28.md](PLAN-subsystem-a-2026-07-28.md). Zmiana którejkolwiek
|
[PLAN-subsystem-a-2026-07-28.md](../phases/subsystem-a-naprawa.md). Zmiana którejkolwiek
|
||||||
decyzji wymaga aktualizacji tego pliku z nową datą.
|
decyzji wymaga aktualizacji tego pliku z nową datą.
|
||||||
|
|
||||||
## Dwa subsystemy (2026-07-28)
|
## Dwa subsystemy (2026-07-28)
|
||||||
|
|
@ -42,7 +42,7 @@ Stack ai-cluster na vps (openclaw, codex-worker, planner-worker, service-ops-wor
|
||||||
redis, mosquitto) jest **wygaszany, nie migrowany**. Bus `codex/*` martwy od
|
redis, mosquitto) jest **wygaszany, nie migrowany**. Bus `codex/*` martwy od
|
||||||
2026-06-09 (zero nowych połączeń). Branch `task/ai-cluster-solaria` zostaje
|
2026-06-09 (zero nowych połączeń). Branch `task/ai-cluster-solaria` zostaje
|
||||||
**niezmergowany** — pełni rolę dokumentacji. Kontenery na vps zostaną zatrzymane w
|
**niezmergowany** — pełni rolę dokumentacji. Kontenery na vps zostaną zatrzymane w
|
||||||
osobnej, nadzorowanej sesji. Szczegóły: [ai-cluster-LEGACY.md](ai-cluster-LEGACY.md).
|
osobnej, nadzorowanej sesji. Szczegóły: [ai-cluster-LEGACY.md](ai-cluster-legacy.md).
|
||||||
|
|
||||||
## Approvale zostają HITL (2026-07-28)
|
## Approvale zostają HITL (2026-07-28)
|
||||||
|
|
||||||
|
|
|
||||||
625
kb/decisions/backlog-aktywne.md
Normal file
625
kb/decisions/backlog-aktywne.md
Normal file
|
|
@ -0,0 +1,625 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
## 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/<id>.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
|
||||||
|
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 <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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
29
kb/decisions/backlog-anomaly-detection-liveness.md
Normal file
29
kb/decisions/backlog-anomaly-detection-liveness.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Anomaly detection liveness — mózg uczy się wzorca dobowego per node (pomysł 2026-06-26)
|
||||||
|
|
||||||
|
**Idea**: zamiast statycznych okien czasowych w regułach alertowych (np. "lustro 7-23"),
|
||||||
|
mózg (supervisor/observer) czyta historię metryk z Prometheus (range queries / Grafana)
|
||||||
|
i SAM wykrywa wzorzec dobowy każdego węzła. `up==0` zgodne z nauczonym wzorcem offline
|
||||||
|
(lustro zwykle off nocą, solaria nieregularnie) = NIE anomalia, nie alarmuj. `up==0`
|
||||||
|
odbiegające od wzorca = realna awaria → alert. Inteligencja w mózgu + dane jako źródło
|
||||||
|
wzorca, nie sztywne godziny wpisywane ręcznie.
|
||||||
|
|
||||||
|
**Warunek**: wymaga TYGODNI historii metryk. fleet-prometheus postawiony 2026-06-25 →
|
||||||
|
realne dopiero za ~2-4 tygodnie, gdy uzbiera się wzorzec dobowy.
|
||||||
|
|
||||||
|
**Pułapka**: uczący się system może przeoczyć realną awarię pokrywającą się z typowym
|
||||||
|
oknem offline (statyczna reguła jest głupia, ale przewidywalna). Uwzględnić przy projektowaniu.
|
||||||
|
|
||||||
|
**Na teraz**: targety scrape'owane BEZ polityki alertowej, label tylko `node:`. Prometheus
|
||||||
|
gromadzi historię. Anomaly detection = osobny świadomy projekt później (CC, z testami).
|
||||||
|
|
||||||
|
---
|
||||||
19
kb/decisions/backlog-deploy-host-pusty.md
Normal file
19
kb/decisions/backlog-deploy-host-pusty.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## `scripts/deploy/deploy-host.sh` to pusty plik (2026-08-03)
|
||||||
|
|
||||||
|
**Data**: 2026-08-03
|
||||||
|
**Źródło**: sesja `task/redeploy-fix`.
|
||||||
|
**Problem**: 0-bajtowy, wykonywalny stub w `scripts/deploy/` — wygląda jak
|
||||||
|
entrypoint, nie robi nic. Kandydat do skasowania (jak `deploy-role.sh` w etapie 0).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
41
kb/decisions/backlog-deploy-runner-instalacja.md
Normal file
41
kb/decisions/backlog-deploy-runner-instalacja.md
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## deploy-runner: instalacja na węzłach + E2E redeployu (2026-08-03)
|
||||||
|
|
||||||
|
**Data**: 2026-08-03
|
||||||
|
**Źródło**: sesja `task/redeploy-fix` — recon D14/D15 + OPEN QUESTION 4 (nieopróżniona
|
||||||
|
kolejka akcji).
|
||||||
|
**Było**: `redeploy` nie mógł się wykonać nigdy. Executor odpalał
|
||||||
|
`scripts/deploy/deploy-node.sh <node> <service>` **wewnątrz swojego kontenera** —
|
||||||
|
skrypt ignoruje oba argumenty i wymaga repo w `${HOME}/homelab-codex-ws`
|
||||||
|
(w kontenerze `HOME=/home/homelab`, katalog nie istnieje) → `exit 1` w 18. linii.
|
||||||
|
Za tym stały jeszcze trzy blokady: brak `git`, brak klienta `docker` w obrazie oraz
|
||||||
|
— gdyby przeszedł — deploy **całego zestawu usług hosta executora**, nie węzła
|
||||||
|
z akcji. Stąd `healthcheck_failed` przekierowany 2026-07-29 na `container_restart`
|
||||||
|
i 18 pending / 0 completed.
|
||||||
|
**Zrobione w repo (ta sesja)**: `scripts/deploy/deploy-service.sh` (deploy jednej
|
||||||
|
usługi, wspólny z `deploy-node.sh` — ta sama inwokacja compose, więc ta sama nazwa
|
||||||
|
projektu), `jobs/deploy-runner/` (systemd na hoście: rsync-pull akcji, walidacja,
|
||||||
|
deploy, `action_result` z powrotem), executor dispatchuje `redeploy` do
|
||||||
|
`actions/deploy/<node>/` i rozlicza je jak `container_restart`
|
||||||
|
(`REDEPLOY_TIMEOUT_SECS=900`). 248 testów zielonych.
|
||||||
|
**Do zrobienia (runtime, wymaga operatora)**:
|
||||||
|
1. Deploy control-plane na VPS (nowy executor + `../..:/repo:ro`).
|
||||||
|
2. Instalacja `jobs/deploy-runner/` na vps, piha, solaria — patrz README
|
||||||
|
(„Install (per node)"). Na VPS `VPS_EVENTS_HOST` musi zostać puste.
|
||||||
|
3. E2E na benignej usłudze na PIHA (wzorzec `test-e2e-b` z 2026-07-23), potem
|
||||||
|
opróżnienie kolejki 18 pending — w tym `redeploy-vps-gokapi`.
|
||||||
|
4. SOLARIA: `group_add: "996"` dla node-agenta wciąż niewdrożony (recon 641-649) —
|
||||||
|
dopóki nie wejdzie, `container_restart` tam nie działa (redeploy działa, bo nie
|
||||||
|
idzie przez node-agenta).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
24
kb/decisions/backlog-disk-cleanup-zepsuty.md
Normal file
24
kb/decisions/backlog-disk-cleanup-zepsuty.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## disk_cleanup w executorze jest zepsuty tak samo jak był redeploy (2026-08-03)
|
||||||
|
|
||||||
|
**Data**: 2026-08-03
|
||||||
|
**Źródło**: sesja `task/redeploy-fix` (znalezione przy okazji, poza zakresem zadania).
|
||||||
|
**Problem**: `executor._execute_disk_cleanup()` odpala `ssh oskar@<node> …`, a obraz
|
||||||
|
control-plane (`python:3.11-slim` + `pip install pyyaml`) **nie ma klienta ssh** —
|
||||||
|
`subprocess.run(["ssh", …])` leci `FileNotFoundError`, akcja ląduje w `failed/`.
|
||||||
|
To ta sama klasa błędu co redeploy i sprzeczne z decyzją „bez SSH w executorze".
|
||||||
|
**Fix**: przenieść `disk_cleanup` na model dispatch (node-agent albo deploy-runner —
|
||||||
|
runner ma już hosta i uprawnienia) albo usunąć typ akcji. Do decyzji przy okazji
|
||||||
|
opróżniania kolejki.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
22
kb/decisions/backlog-followupy-etap0.md
Normal file
22
kb/decisions/backlog-followupy-etap0.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Follow-upy z etapu 0 (truth cleanup, 2026-07-29)
|
||||||
|
|
||||||
|
**Źródło**: sesja merge `task/etap0-truth` (topologia: status active|dormant,
|
||||||
|
listy serwisów usunięte z topology.yaml — node-level truth only).
|
||||||
|
|
||||||
|
- **40-register.sh emituje stary schemat topologii** — szablon bloku node'a
|
||||||
|
w `scripts/onboard/steps/40-register.sh` nadal zawiera listę `services:`
|
||||||
|
i nie ma pola `status:`; wyrównać z nowym schematem node-level-only
|
||||||
|
(`inventory/topology.yaml`).
|
||||||
|
- **Historyczny komentarz mqtt_unreachable w observerze** — `scripts/observer/
|
||||||
|
observer.py:866` wspomina routing `mqtt_unreachable -> container_restart`
|
||||||
|
usunięty z supervisora (recon D15); sprzątnąć przy najbliższej edycji pliku.
|
||||||
30
kb/decisions/backlog-kb-serwisy-poza-monitoringiem.md
Normal file
30
kb/decisions/backlog-kb-serwisy-poza-monitoringiem.md
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nowe serwisy KB nie sa w monitoringu (desired-state)
|
||||||
|
|
||||||
|
**Data:** 2026-07-12
|
||||||
|
|
||||||
|
**Problem:** Zdeployowane serwisy filaru dokumentow nie maja wpisow w `hosts/*/services.yaml`
|
||||||
|
i `inventory/topology.yaml`, wiec supervisor/observer ich NIE WIDZA w desired-state:
|
||||||
|
- `paperless` + `paperless-db` + `paperless-broker` (PIHA) — Deploy 1, 2026-07-10
|
||||||
|
- `paperless-worker` (SOLARIA) — Deploy 2, 2026-07-12 (SOLARIA ma tam tylko `node-agent`)
|
||||||
|
|
||||||
|
**Skutek:** drift nie jest wykrywany. Jesli worker padnie i nie wstanie, albo paperless
|
||||||
|
przestanie dzialac — agent system tego nie zglosi. Dowiesz sie dopiero po tym, ze kolejka
|
||||||
|
nie jest przetwarzana / strona nie odpowiada.
|
||||||
|
|
||||||
|
**Fix:** dodac wpisy do `hosts/piha/services.yaml`, `hosts/solaria/services.yaml`,
|
||||||
|
`inventory/topology.yaml`. Zweryfikowac ze observer/supervisor je widza (healthcheck,
|
||||||
|
liveness). Dotyczy tez przyszlych: nextcloud, gokapi.
|
||||||
|
|
||||||
|
**Zasada na przyszlosc:** rejestracja w services.yaml/topology to CZESC deployu, nie osobny
|
||||||
|
krok "kiedys" — inaczej kazdy nowy serwis to slepy punkt monitoringu.
|
||||||
|
|
||||||
31
kb/decisions/backlog-m1-solaria-prune-mitigation.md
Normal file
31
kb/decisions/backlog-m1-solaria-prune-mitigation.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-04
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
- ../incidents/2026-07-30-ollama-solaria-vanish.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## M1 aktywna na SOLARII — cleanup node-agenta wyłączony do czasu R1 (2026-08-04)
|
||||||
|
|
||||||
|
**Data**: 2026-08-04
|
||||||
|
**Źródło**: `kb/incidents/2026-07-30-ollama-solaria-vanish.md` (§7, M1).
|
||||||
|
**Stan**: w `hosts/solaria/runtime/node-agent/docker-compose.override.yml` ustawiono
|
||||||
|
`NODE_TYPE=lte_node` (było `ai_node`) na czas backfillu embed (faza mailowa KB).
|
||||||
|
`lte_node` powoduje wczesny return w `run_safe_cleanup()`, więc na SOLARII nie działa
|
||||||
|
niefiltrowany `docker container prune` kasujący zatrzymane kontenery w ≤60 s —
|
||||||
|
łącznie z tymi, które mają `restart: unless-stopped` i zostały zatrzymane świadomie.
|
||||||
|
`self.node_type` jest czytane wyłącznie w `run_safe_cleanup()` i dwóch liniach logu,
|
||||||
|
więc monitoring, eventy i dispatch akcji działają bez zmian.
|
||||||
|
**Skutek uboczny**: `lte_node` pomija CAŁY cleanup — na czas mitygacji nie są sprzątane
|
||||||
|
dangling images ani build cache. Pilnować miejsca na dysku SOLARII.
|
||||||
|
**Nie zdeployowane** — zmiana jest tylko w repo (branch `task/m1-prune-mitigation`);
|
||||||
|
wchodzi przy najbliższym redeployu node-agenta na SOLARII.
|
||||||
|
**Zdjąć po**: wdrożeniu R1 (filtrowanie prune po restart policy / labelu compose) na tym
|
||||||
|
nodzie — wtedy przywrócić `NODE_TYPE=ai_node`. R1–R3 w toku po stronie subsystemu A.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
83
kb/decisions/backlog-rozjazdy-repo-rzeczywistosc.md
Normal file
83
kb/decisions/backlog-rozjazdy-repo-rzeczywistosc.md
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rozjazdy repo<->rzeczywistosc (z inwentaryzacji 2026-06-30)
|
||||||
|
**Zrodlo**: `kb/subsystems/fleet-inventory.md` (23 rozjazdy, pelna tabela tam).
|
||||||
|
**Weryfikacja 2026-07-02**: `kb/subsystems/fleet-inventory-verify.md` — bilans:
|
||||||
|
20 wciaz aktualnych, 2 zmienione, 1 wyjasniony (storage SOLARIA = partycja Windows
|
||||||
|
dual-boot, NIE rozjazd — zdjety z listy).
|
||||||
|
Ponizej te wymagajace akcji, pogrupowane wg ryzyka. Naprawa = osobny task/kilka.
|
||||||
|
|
||||||
|
### Grupa A — czyste docs, zero ryzyka
|
||||||
|
- ✅ ZROBIONE (2026-07-02, commit `886bc85`) — **forgejo** `service.yaml owner_node`:
|
||||||
|
saturn -> piha (biega na PIHA always-on)
|
||||||
|
- ✅ ZROBIONE (2026-07-02, commit `886bc85`) — **mosquitto** `service.yaml owner_node`:
|
||||||
|
piha -> vps (biega na VPS, nie na PIHA)
|
||||||
|
- **capabilities SATURN**: RAM 8 -> 14GiB; dysk sd-card 64GB -> /dev/sda 159GB
|
||||||
|
- **capabilities SOLARIA**: CPU 24 -> 32 nproc
|
||||||
|
- **`hosts/saturn/services.yaml`** nie istnieje — 5 kontenerow bez deklaracji
|
||||||
|
- **`hosts/vps/services.yaml`** niekompletne (4 z 9 z topology); **solaria** tez (brak planner-agent)
|
||||||
|
|
||||||
|
### Grupa B — wymaga decyzji
|
||||||
|
- **npm x2**: PIHA (LAN ingress :80/:443) + VPS (public). Repo zna jedna (owner=vps).
|
||||||
|
Decyzja: zostawic oba (intentional, wildcard cert via NPM@PIHA) czy usunac PIHA?
|
||||||
|
Jesli oba zamierzone -> dodac piha do service.yaml + hosts/piha.
|
||||||
|
- ✅ ZROBIONE (2026-07-02) — **control-plane na SATURN**: `docker compose down`
|
||||||
|
(wolumeny zachowane). Supervisor byl SLEPY (brak mountu repo, WARNING loop
|
||||||
|
"Hosts directory /repo/hosts does not exist" co 30s) — zero ryzyka zdublowanych
|
||||||
|
remediacji przez te 3 dni. Jedyny control-plane = produkcyjny na VPS.
|
||||||
|
- **ollama**: `service.yaml owner=solaria` ale NIE biega. Wdrozyc czy wyrzucic z repo?
|
||||||
|
|
||||||
|
### Grupa C — sprzatanie
|
||||||
|
- **control-plane-ui healthcheck**: uzywa `curl` ktorego NIE MA w obrazie -> failuje w
|
||||||
|
kolko -> UNHEALTHY + log spam (4.2G syslog na SATURN). Fix: wget/nc w healthcheck
|
||||||
|
albo curl w Dockerfile. (Przyczyna rozjazdu #6 znaleziona przy gaszeniu dysku.)
|
||||||
|
- **homeassistant5 na PIHA** (HA "ken" :8123) niedeklarowany -> dodac do hosts/piha + topology
|
||||||
|
- **VPS**: outline-postgres-1 anonimowy image (4e6e670bb069) -> named tag;
|
||||||
|
humanai-landing/mailer/umami do repo. ~~joplin-db postgres:18 -> 17/16~~
|
||||||
|
(ocena zdezaktualizowana 2026-07-02: PG18 GA od 09/2025, nie pre-release — bez akcji)
|
||||||
|
- **PIHA: 33 shadow kontenery** poza GitOps (immich, vaultwarden, wikijs, actual,
|
||||||
|
audiobookshelf, elasticsearch, grafana, prom, portainer, code-server, diskover...)
|
||||||
|
-> audyt + stopniowo do hosts/piha/services.yaml
|
||||||
|
- **zigbee2mqtt** topology mowi chelsty-infra, biega na PIHA -> poprawic topology
|
||||||
|
- **stability-agent / node_exporter** owner_node single, biegaja wielomiejscowo -> per-host
|
||||||
|
|
||||||
|
### Followupy z weryfikacji + rozbrajania min (2026-07-02)
|
||||||
|
**Zrodlo**: `kb/subsystems/fleet-inventory-verify.md` + sesja 2026-07-02.
|
||||||
|
Zgloszone przy fixie owner_node (`886bc85`), swiadomie NIE ruszone — osobne decyzje.
|
||||||
|
|
||||||
|
- **forgejo** brak wpisu w `hosts/piha/services.yaml`; **mosquitto** brak
|
||||||
|
w `hosts/vps/services.yaml` — schemat hostowy wymaga role/exposure/depends_on
|
||||||
|
(miny #2/#3/#16 z audytu).
|
||||||
|
- **mosquitto na VPS bez mem_limit override** w `hosts/vps/runtime/` —
|
||||||
|
narusza konwencje CLAUDE.md (kazdy serwis VPS deklaruje mem_limit).
|
||||||
|
- **drugi mosquitto na chelsty-infra** (offline'owa instancja) — pojedyncze
|
||||||
|
`owner_node` jej nie opisuje; wzorzec per-host jak stability-agent /
|
||||||
|
node_exporter (miny #17/#18).
|
||||||
|
- **topology.yaml:75**: mosquitto zadeklarowany tez jako komponent ai-cluster —
|
||||||
|
rozstrzygnac, czyj jest broker :1883.
|
||||||
|
- **pi-watchtower-1 na LUSTRO w restart-loopie** (nowe z reconu; node-agent healthy).
|
||||||
|
- **alias `lustro` nie rezolwuje z SOLARII** (nowe z reconu).
|
||||||
|
- **fleet-prometheus bez formalnego override mem_limit** w `hosts/vps/runtime/` —
|
||||||
|
limit siedzi w bazowym compose (kosmetyka).
|
||||||
|
|
||||||
|
### Po odchudzaniu PIHA (2026-07-02, faza 2 modulu 0)
|
||||||
|
- **llm-gateway: zlokalizowac/zarchiwizowac zrodlo** — kod (wlasny FastAPI router ->
|
||||||
|
Ollama@SOLARIA) moze zyc TYLKO w `/opt/llm-gateway` na PIHA, bez gita; przeszukanie
|
||||||
|
PIHA i repo nie znalazlo innej kopii. Zarchiwizowac do repo/Forgejo zanim padnie nosnik.
|
||||||
|
- **Prometheus@PIHA: target llm-gateway blednie nazwany `watchtower`** — celuje w :8080
|
||||||
|
i odpytuje `/v1/metrics`, dostaje wieczne 404 (llm-gateway nie serwuje metryk).
|
||||||
|
Naprawic nazwe/endpoint albo usunac target.
|
||||||
|
|
||||||
|
### Tech debt SATURN (z gaszenia dysku 2026-06-30)
|
||||||
|
- **`/opt/anaconda3` 16G** — najwiekszy pojedynczy zjadacz dysku (env-y Pythona). Decyzja Oskara kiedy/czy czyscic.
|
||||||
|
- Dysk 91% -> 83% ugaszone (docker prune + journal + syslog), ale `/home` zaszyfrowany
|
||||||
|
i ciasny strukturalnie. SATURN dzwiga dev + drugi control-plane + agent-webui — napiecie.
|
||||||
|
|
||||||
43
kb/decisions/backlog-uid-gid-flota.md
Normal file
43
kb/decisions/backlog-uid-gid-flota.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tech-debt: globalny porządek uid/gid/uprawnień we flocie (2026-07-10)
|
||||||
|
|
||||||
|
**Diagnoza.** Flota NIE ma spójnej mapy uid/gid. "oskar" ma różne uid per host
|
||||||
|
(PIHA: 1004, inne hosty: prawdopodobnie 1000/inne). Kontenery agentów zakładają
|
||||||
|
uid 1000 (user "homelab"). Bind-mounty przenoszą SUROWE uid (nie nazwy) między
|
||||||
|
hostem a kontenerem → gdy uid hosta ≠ uid zakładany przez kontener, pliki stają
|
||||||
|
się "cudze" i wybucha cicha awaria (klucz nieczytelny, rsync nie tworzy plików,
|
||||||
|
socket permission denied). To NIE są przypadki — to systemowy brak kanonicznej
|
||||||
|
mapy uid/gid.
|
||||||
|
|
||||||
|
**Historia incydentów (dowód że systemowe):**
|
||||||
|
- 2026-07-10: node-agent PIHA (uid 1000 homelab) montował /home/oskar/.ssh (pliki
|
||||||
|
uid 1004) → "Load key id_rsa: Permission denied" → rsync padał → 21 dni bez
|
||||||
|
eventów (wykryte przez shadow-read). Fix: dedykowany /opt/homelab/agent-ssh
|
||||||
|
chown 1000.
|
||||||
|
- Wcześniej: oskar spoza grupy `aerbot` na VPS → rsync push nie tworzył plików →
|
||||||
|
brak cleanup → 8-dniowa cicha awaria floty. Fix: usermod -aG aerbot oskar.
|
||||||
|
- 2026-07-10 (świeże, PENDING): node-agent PIHA "Docker unavailable: PermissionError(13)"
|
||||||
|
po recreate — agent nie czyta /var/run/docker.sock (grupa docker/uid). Osobny od
|
||||||
|
shippingu (nie blokuje eventów), ale ten sam rodzaj problemu — do naprawy
|
||||||
|
(grupa docker w kontenerze / gid socketu).
|
||||||
|
- LUSTRO uid pi=1000 vs PIHA oskar=1004 — różne uid "pierwszego usera" per host.
|
||||||
|
|
||||||
|
**Kierunek naprawy (do rozważenia, osobny projekt):**
|
||||||
|
- Ustalić KANONICZNE uid/gid per rola: agent=1000 wszędzie; dedykowane grupy dla
|
||||||
|
współdzielonych zasobów (aerbot dla events/rsync-sink na VPS, docker dla socketu).
|
||||||
|
- Audyt `id <user>` na KAŻDYM hoście floty (saturn/solaria/piha/vps/lustro) —
|
||||||
|
zmapować realne uid/gid, udokumentować rozjazdy.
|
||||||
|
- Rozważyć deklaratywny zapis oczekiwanych uid/gid w hosts/*/host.yaml lub
|
||||||
|
capabilities.yaml (żeby deploy mógł weryfikować/wymuszać spójność).
|
||||||
|
- Agenci NIE powinni montować prywatnego .ssh użytkownika — zawsze dedykowany
|
||||||
|
katalog z własnym kluczem pod właściwym uid (wzorzec z fixa 2026-07-10).
|
||||||
|
|
||||||
223
kb/decisions/backlog-zamkniete.md
Normal file
223
kb/decisions/backlog-zamkniete.md
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Zamknięte
|
||||||
|
|
||||||
|
### Publiczny bind `operator_ui.py:18180` na VPS bez autoryzacji — NAPRAWIONE (2026-07-22, commit `9a5c160`)
|
||||||
|
|
||||||
|
**Data**: 2026-07-22
|
||||||
|
**Źródło**: sesja 2026-07-22/23 (`docs/sessions/2026-07-23-control-plane-remediation-e2e.md`)
|
||||||
|
**Było**: `operator_ui.py` (port 18180) nasłuchiwał na `0.0.0.0` na publicznym VPS
|
||||||
|
(`135.181.153.108`) bez żadnej autoryzacji. `curl` z zewnątrz do `/actions` zwracał
|
||||||
|
HTTP 200. `do_POST /action/mutate` przenosi akcje między stanami WŁĄCZNIE z
|
||||||
|
`"approved"` — dowolna osoba z internetu mogła zatwierdzić akcję remediacyjną.
|
||||||
|
Jedyne co chroniło do tej pory: executor nie umiał jeszcze wykonać akcji (brak SSH,
|
||||||
|
patrz wpis niżej) — przypadek, nie zabezpieczenie.
|
||||||
|
**Naprawione**: dual-bind wg wzorca fleet-prometheus — `127.0.0.1:18180:8080` +
|
||||||
|
`${TAILSCALE_BIND_IP}:18180:8080`, nowy `services/control-plane/env.example`.
|
||||||
|
Zweryfikowane po deployu: publiczny IP → HTTP 000, Tailscale → HTTP 200. Konsumenty
|
||||||
|
(node-agent VPS, materializer PIHA) nietknięte.
|
||||||
|
**Footgun zapamiętany**: brak `.env` → `docker compose` tylko OSTRZEGA i po cichu
|
||||||
|
wraca do bindu `0.0.0.0`, nie failuje — patrz wpis „deploy-local.sh: brak twardego
|
||||||
|
checka .env" w Aktywnych.
|
||||||
|
**Pozostaje osobno**: `operator_ui.py` nadal bez żadnej autoryzacji (bind zamknięty
|
||||||
|
chroni przed internetem, nie przed kimkolwiek w mesh Tailscale) — patrz Aktywne.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Remediacja floty bez SSH: executor→node-agent pull przez rsync — ZROBIONE (2026-07-22, commit `2dac154`), E2E potwierdzone 2026-07-23
|
||||||
|
|
||||||
|
**Data**: 2026-07-22 (implementacja), 2026-07-23 (pierwszy udany cykl E2E)
|
||||||
|
**Źródło**: sesja 2026-07-22/23 (`docs/sessions/2026-07-23-control-plane-remediation-e2e.md`)
|
||||||
|
**Było**: łańcuch supervisor→pending→approved→running działał, ale executor próbował
|
||||||
|
`ssh oskar@{node} docker restart {container}` — kontener control-plane nie ma klienta
|
||||||
|
ssh, klucza, ani rozwiązywalnych nazw węzłów. Wykonanie zawsze failowało.
|
||||||
|
**Decyzja architektoniczna**: bez SSH w executorze (kontener na publicznym VPS z
|
||||||
|
powłoką na całą flotę = zły blast radius). Kierunek PULL: executor zleca (zapis
|
||||||
|
`actions/dispatch/<node>/<action_id>.json`), node-agent na docelowym węźle wykonuje
|
||||||
|
lokalnie przez własny `docker.sock`, wynik wraca eventem `action_result` przez
|
||||||
|
istniejący rsync-push. VPS nigdy nie inicjuje połączenia do węzła.
|
||||||
|
**Zabezpieczenia**: walidacja `node == self.node_name`; whitelist typów akcji =
|
||||||
|
`{container_restart}`; guard przed restartem samego node-agenta; brak wykonywania
|
||||||
|
dowolnych poleceń z payloadu; idempotencja (ponowne zlecenie = no-op). 183 testy.
|
||||||
|
**Potwierdzone w boju (2026-07-23)**: cykl `test-e2e-b` — Executing → Dispatched →
|
||||||
|
Completed w 31 sekund, `node_exporter` na PIHA realnie zrestartowany (uptime 30h→
|
||||||
|
minuty), zero połączeń SSH. Pierwszy w historii systemu pełny cykl remediacji.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Uprawnienia `actions/` na PIHA (uid/gid oskar 1004 vs kontener 1000) — NAPRAWIONE ręcznie (2026-07-23, poza repo)
|
||||||
|
|
||||||
|
**Data**: 2026-07-23
|
||||||
|
**Źródło**: sesja 2026-07-22/23 (`docs/sessions/2026-07-23-control-plane-remediation-e2e.md`)
|
||||||
|
**Było**: pierwszy test E2E remediacji bez SSH padał — agent logował `[Errno 13]
|
||||||
|
Permission denied: /opt/homelab/actions/dispatch` co cykl. `/opt/homelab/actions`
|
||||||
|
było `oskar:oskar drwxr-xr-x` (utworzone w maju), a działający wzorzec to
|
||||||
|
`/opt/homelab/events` = `oskar:pi drwxrwsr-x` (grupa `pi`, zapis grupowy, setgid).
|
||||||
|
Ten sam motyw uid/gid (host oskar 1004 vs kontener 1000) uderzył już czwarty raz —
|
||||||
|
patrz sekcja „Tech-debt: globalny porządek uid/gid/uprawnień we flocie".
|
||||||
|
**Naprawione (ręcznie, tylko na PIHA)**: `chgrp -R pi` + `chmod -R g+w` + `chmod g+s`
|
||||||
|
na `/opt/homelab/actions`. Executor zachował się poprawnie podczas awarii: po 300s
|
||||||
|
timeoutu przeniósł akcję do `failed` z czytelnym powodem, nic nie zawisło.
|
||||||
|
**Pozostaje osobno**: fix zastosowany TYLKO na PIHA — SOLARIA i lustro
|
||||||
|
niezweryfikowane; docelowy fix systemowy to node-agent tworzący
|
||||||
|
`dispatch/<node>/` z właściwymi prawami przy starcie — patrz Aktywne.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Supervisor: pętla zamrożona ~24h, healthy ale nie tika — NAPRAWIONE (2026-07-16, commit `409b583`)
|
||||||
|
|
||||||
|
**Data**: 2026-07-16
|
||||||
|
**Źródło**: sesja 2026-07-16 (`docs/sessions/2026-07-16.md`) — wątek control-plane
|
||||||
|
**Było**: kontener supervisora `healthy`, ale pętla `reconcile()` nie tikała od ~24h,
|
||||||
|
zero logów. Root cause zweryfikowany na `/proc` (`State:S hrtimer_nanosleep`, NIE
|
||||||
|
deadlock): `glob` po `EVENTS_DIR` co cykl przy 358k plikach → cykl przekracza brak
|
||||||
|
timeoutu → nigdy się nie kończy. Logi na DEBUG maskowały objaw.
|
||||||
|
**Naprawione**: każdy cykl w `ThreadPoolExecutor` z `future.result(timeout=90s,
|
||||||
|
env SUPERVISOR_RECONCILE_TIMEOUT)`; try/except owija cykl (wyjątek nie zabija pętli);
|
||||||
|
tick-log co 10 cykli (`SUPERVISOR_TICK_LOG_EVERY`) na INFO; healthcheck sprawdza
|
||||||
|
świeżość heartbeat, nie tylko czy proces żyje. Zweryfikowane w boju: pętla tika
|
||||||
|
(cycle #340→#480), cykl #1 timeoutował ale pętla kontynuowała = odporność działa.
|
||||||
|
**Lekcja**: „healthy kontener ≠ tikająca pętla" — healthcheck musi sprawdzać
|
||||||
|
świeżość ostatniego cyklu, nie samo czy proces odpowiada.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Event flood 358k plików + retencja martwa od fixu checkpointu — NAPRAWIONE (2026-07-16, commit `dff76ec`)
|
||||||
|
|
||||||
|
**Data**: 2026-07-16
|
||||||
|
**Źródło**: sesja 2026-07-16 (`docs/sessions/2026-07-16.md`) — wątek control-plane
|
||||||
|
**Było**: `EVENTS_DIR` = 358k plików, 91% to `service_healthy` emitowany co cykl per
|
||||||
|
serwis (stan-jako-zdarzenie, antywzorzec). Retencja `_cleanup_control_plane_fs()`
|
||||||
|
była martwa od fixu checkpointu `d5139c9` (2026-07-15, patrz „Bug: checkpoint
|
||||||
|
observera po ścieżce leksykalnej" niżej) — porównanie `str(ścieżka) <= checkpoint_int`
|
||||||
|
rzucało `TypeError` cicho łapany przez szeroki `except` → backlog rósł bez ograniczenia.
|
||||||
|
Naprawiając checkpoint wczoraj, złamaliśmy retencję, która na nim polegała.
|
||||||
|
**Naprawione**: (a) node-agent emituje `service_healthy` tylko na transition
|
||||||
|
unhealthy→healthy (funkcja dla `observer.process_event` zachowana); (b) retencja
|
||||||
|
naprawiona epoch-do-epoch; (c) `scripts/maintenance/cleanup_event_backlog.py`
|
||||||
|
(dry-run + `--apply`). 150 testów pass. Cleanup wykonany na PIHA+VPS: 272 232 pliki
|
||||||
|
usunięte, backlog 358k→12,7k. **Wynik**: reconcile supervisora przestał timeoutować.
|
||||||
|
**Lekcja**: migracja typu pola (ścieżka→epoch int) musi audytować WSZYSTKICH
|
||||||
|
konsumentów tego pola — szeroki `except` maskował dokładnie tę klasę regresji.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Ghost kontenery w panelu (Problem B) — ZNIKNĘŁY (potwierdzone reconem 2026-07-02)
|
||||||
|
|
||||||
|
> ⚠️ ZDEZAKTUALIZOWANE 2026-07-06: ghosty znów widoczne na VPS — patrz wpis
|
||||||
|
> „Ghosty B WRÓCIŁY" w Aktywnych (`docs/sessions/2026-07-06.md`).
|
||||||
|
|
||||||
|
**Data**: 2026-06-24 (wykryte), 2026-07-02 (zamknięte)
|
||||||
|
**Źródło**: sesje 2026-06-24/25/26; recon `kb/subsystems/fleet-inventory-verify.md`
|
||||||
|
**Było**: martwe kontenery ze starych project-name'ów
|
||||||
|
(`8547b46c0317_control-plane-supervisor` itp.) raportowane przez observera jako
|
||||||
|
`error` → `System Status ERROR` w panelu mimo zdrowego mózgu.
|
||||||
|
**Zamknięte**: recon 2026-07-02 — 24 kontenery na VPS, ZERO hash-prefixed.
|
||||||
|
Prawdopodobnie recreate'y z kolejnych deployów je zmiotły. Zero akcji ręcznej.
|
||||||
|
Rozważenie czyszczenia obcych project-name przy deployu — już nieaktualne
|
||||||
|
(fix A `3b71707` blokuje źródło divergence).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### brain-watchdog: poll Prometheus — POTWIERDZONY (recon 2026-07-02)
|
||||||
|
|
||||||
|
**Data**: 2026-06-30 (pending), 2026-07-02 (zamknięte)
|
||||||
|
**Źródło**: recon `kb/subsystems/fleet-inventory-verify.md`
|
||||||
|
**Było**: log startowy nie wypisuje `PROMETHEUS_URL` → brak pewności, że polling
|
||||||
|
aktywny; diagnoza opierała się na `.env` i braku błędów.
|
||||||
|
**Zamknięte**: recon potwierdził — obraz zbudowany po `62d6fc0`, `PROMETHEUS_URL`
|
||||||
|
w `.env` I w env kontenera, zero `poll failed` w logach. Poll aktywny.
|
||||||
|
Jednolinijkowy log startowy (`polling enabled/disabled`) pozostaje opcjonalną
|
||||||
|
kosmetyką. ✅ Pełne end-to-end (firing → Telegram) POTWIERDZONE 2026-07-06
|
||||||
|
testem `AlertTestEtap0` (Etap 0 cutoveru, `docs/sessions/2026-07-06.md`) —
|
||||||
|
bez czekania na realną awarię.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Miny #1/#2/#3 z weryfikacji inwentaryzacji — ROZBROJONE (2026-07-02)
|
||||||
|
|
||||||
|
**Źródło**: `kb/subsystems/fleet-inventory-verify.md`, sesja
|
||||||
|
`docs/sessions/2026-07-02.md` (tam szczegóły i lekcje).
|
||||||
|
- **#1 PIHA checkout**: gałąź wciąż `task/kb-gmail-import` po resecie z 2026-06-30
|
||||||
|
(reset --hard przesuwa gałąź, nie przełącza) → `checkout master && pull`,
|
||||||
|
30 commitów nadrobione.
|
||||||
|
- **#2 control-plane na SATURN**: supervisor ślepy (brak mountu repo) →
|
||||||
|
`docker compose down`, wolumeny zachowane. Jedyny mózg = VPS.
|
||||||
|
- **#3 owner_node**: forgejo→piha, mosquitto→vps (commit `886bc85`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔴 KRYTYCZNY — `deploy.sh vps` niszczył control-plane — NAPRAWIONE (commit `3b71707`)
|
||||||
|
|
||||||
|
**Data**: 2026-06-24 (wykryte), 2026-06-25 (incydent w produkcji), 2026-06-26 (naprawione)
|
||||||
|
**Źródło**: sesja 2026-06-24 + 2026-06-25 + 2026-06-26 (`docs/sessions/2026-06-26.md`)
|
||||||
|
**Było (Problem A)**: `control-plane` w `hosts/vps/services.yaml` jako zwykły serwis
|
||||||
|
pętli `deploy-node.sh`. Pętla używała innego `COMPOSE_PROJECT_NAME` niż `deploy-local.sh`
|
||||||
|
(cwd=`services/control-plane`). Niezgodność → Recreate → `No such container:
|
||||||
|
<hash>_control-plane-observer` → `set -e` przerywa pętlę → observer/supervisor/executor/ui
|
||||||
|
znikają. Każdy `deploy.sh vps` rozkładał mózg (potwierdzone w produkcji 2026-06-25).
|
||||||
|
**Naprawione**: guard w `deploy-node.sh` pomijający serwisy z własnym
|
||||||
|
`services/<svc>/deploy-local.sh`. `control-plane` ZOSTAJE w `services.yaml` (gate
|
||||||
|
pytest+build nadal go testuje), pomijana jest tylko destrukcyjna pętla deployu.
|
||||||
|
**Potwierdzone w boju**: `deploy.sh vps` wypisał `Skipping control-plane: ma własną
|
||||||
|
ścieżkę deployu`, mózg `Up 25h healthy`, nietknięty.
|
||||||
|
**Pozostało osobno**: ghosty z poprzednich rozjazdów (Problem B — patrz Aktywne).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Flaky testy control-plane — state-leak w pytest — NAPRAWIONE (commit `992ff7c`)
|
||||||
|
|
||||||
|
**Data**: 2026-06-24 (zgłoszone), 2026-06-25 (naprawione)
|
||||||
|
**Źródło**: sesja 2026-06-24 + sesja 2026-06-25 (`docs/sessions/2026-06-25.md`)
|
||||||
|
**Było**: `test_incident_lifecycle.py` flaky przez state-leak — `OBSERVER_STATE_FILE`
|
||||||
|
wyprowadzany przy imporcie, helpery patchowały `STATE_DIR` ale nie `OBSERVER_STATE_FILE` →
|
||||||
|
checkpointy pisane na realny dysk `/opt/homelab/state/` z ścieżkami otagowanymi numerem
|
||||||
|
przebiegu pytest. Gate deploy.sh czerwony przy zdrowym kodzie.
|
||||||
|
**Naprawione**: autouse monkeypatch fixture redirectujący WSZYSTKIE ścieżki stanu w tym
|
||||||
|
`OBSERVER_STATE_FILE`; usunięto buggy `_make_observer`; posprzątano zatruty realny checkpoint.
|
||||||
|
Weryfikacja: 6/6 przebiegów → 28 passed. Gate rzetelny.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### deploy-node.sh — brak `--env-file` (bind 0.0.0.0) — NAPRAWIONE (commit `686aca7`)
|
||||||
|
|
||||||
|
**Data**: 2026-06-25
|
||||||
|
**Źródło**: sesja 2026-06-25 (`docs/sessions/2026-06-25.md`)
|
||||||
|
**Było**: `deploy-node.sh` nie przekazywał `--env-file` do `compose up` → zmienne `.env`
|
||||||
|
(jak `TAILSCALE_BIND_IP`) interpolowały się do pustego stringa → bind `0.0.0.0` zamiast
|
||||||
|
Tailscale IP. Potencjalna dziura na publicznym VPS.
|
||||||
|
**Naprawione**: guard `if [ -f "services/<svc>/.env" ]` + `--env-file` per-serwis przed
|
||||||
|
`docker compose up`. Worktree `task/deploy-envfile-fix`, merge ff-only.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 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)*
|
||||||
|
|
||||||
|
|
@ -20,5 +20,5 @@ exited at line 18 with `Error: Repository not found`. Behind that failure sat
|
||||||
three more: no `git`, no `docker` CLI in the image, and — had it ever got that
|
three more: no `git`, no `docker` CLI in the image, and — had it ever got that
|
||||||
far — it would have deployed the **executor host's** entire service set, not the
|
far — it would have deployed the **executor host's** entire service set, not the
|
||||||
action's target node/service. Every `healthcheck_failed → redeploy` dead-ended
|
action's target node/service. Every `healthcheck_failed → redeploy` dead-ended
|
||||||
(recon `docs/architecture/RECON-multiagent-2026-07-27.md`, D14/D15).
|
(recon `kb/subsystems/recon-multiagent.md`, D14/D15).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ links:
|
||||||
Status: **phase 1 (partial)**. `scripts/ha/deploy.sh` implements the write
|
Status: **phase 1 (partial)**. `scripts/ha/deploy.sh` implements the write
|
||||||
path for the `api` adapter's automations/scripts/scenes scope (see "Deploy
|
path for the `api` adapter's automations/scripts/scenes scope (see "Deploy
|
||||||
path" and "Sync model" below); dashboards/helpers and the `docker-exec`
|
path" and "Sync model" below); dashboards/helpers and the `docker-exec`
|
||||||
adapter have no write path yet. See `docs/backlog.md` for the tracking
|
adapter have no write path yet. See `kb/phases/backlog.md` for the tracking
|
||||||
entry.
|
entry.
|
||||||
|
|
||||||
## Phasing
|
## Phasing
|
||||||
|
|
@ -59,7 +59,7 @@ behind a common interface (`import.sh`/eventual `deploy.sh <instance>`):
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `ken` (RPi4, HAOS, LAN `192.168.31.7:8123`) | **api** | Canonical home instance since the 2026-07-22 cutover (see Incident log). HAOS has no SSH access, so there is no `docker exec`/filesystem path — only the HA REST/websocket API is reachable. Full `/config` import is deferred until an alternative access path exists; for now the api adapter's import scope is limited to what the API exposes: automations, scripts, scenes, dashboards. |
|
| `ken` (RPi4, HAOS, LAN `192.168.31.7:8123`) | **api** | Canonical home instance since the 2026-07-22 cutover (see Incident log). HAOS has no SSH access, so there is no `docker exec`/filesystem path — only the HA REST/websocket API is reachable. Full `/config` import is deferred until an alternative access path exists; for now the api adapter's import scope is limited to what the API exposes: automations, scripts, scenes, dashboards. |
|
||||||
| `ken-legacy` (piha, container `homeassistant5`) | **docker-exec over SSH** (archive-only) | Pre-migration container instance, superseded by `ken` at 31.7 (see Incident log) — same container filesystem access as the old `ken` entry (`ssh oskar@piha "docker exec homeassistant5 ..."`). Import only, for historical reference; never a deploy target. |
|
| `ken-legacy` (piha, container `homeassistant5`) | **docker-exec over SSH** (archive-only) | Pre-migration container instance, superseded by `ken` at 31.7 (see Incident log) — same container filesystem access as the old `ken` entry (`ssh oskar@piha "docker exec homeassistant5 ..."`). Import only, for historical reference; never a deploy target. |
|
||||||
| `chelsty-ha` | **api** | Reachable over Tailscale at `100.70.180.90:8123` (confirmed working path — `services/ha-diag-agent/DEPLOY.md` already curls this for health checks). Config-as-code deploy will reuse the same reachability, calling the HA REST/websocket API rather than shelling into the container. |
|
| `chelsty-ha` | **api** | Reachable over Tailscale at `100.70.180.90:8123` (confirmed working path — `kb/runbooks/ha-diag-agent-deploy.md` already curls this for health checks). Config-as-code deploy will reuse the same reachability, calling the HA REST/websocket API rather than shelling into the container. |
|
||||||
|
|
||||||
**Open**: a `file` adapter (direct bind-mount / SSH `rsync` to the config
|
**Open**: a `file` adapter (direct bind-mount / SSH `rsync` to the config
|
||||||
directory, bypassing `docker exec`) is worth revisiting once SSH access to
|
directory, bypassing `docker exec`) is worth revisiting once SSH access to
|
||||||
|
|
@ -124,7 +124,7 @@ copied into the repo.
|
||||||
- A dedicated `deploy_agent` HA user account (admin rights, **local-only**
|
- A dedicated `deploy_agent` HA user account (admin rights, **local-only**
|
||||||
— never exposed through the public API/ingress) is created per instance,
|
— never exposed through the public API/ingress) is created per instance,
|
||||||
mirroring the existing `diag_agent` account pattern documented in
|
mirroring the existing `diag_agent` account pattern documented in
|
||||||
`services/ha-diag-agent/DEPLOY.md`. Reusing `diag_agent` is explicitly
|
`kb/runbooks/ha-diag-agent-deploy.md`. Reusing `diag_agent` is explicitly
|
||||||
rejected — deploy tooling and the diagnostic agent must be revocable
|
rejected — deploy tooling and the diagnostic agent must be revocable
|
||||||
independently.
|
independently.
|
||||||
- Long-lived access tokens for `deploy_agent` live at
|
- Long-lived access tokens for `deploy_agent` live at
|
||||||
|
|
@ -150,7 +150,7 @@ Zobacz `docs/audyt-automatyzacji-2026-07-23.md` (sekcja "Do decyzji operatora",
|
||||||
17 punktów) — poniżej wyłącznie decyzje, które doprowadziły do zmian w
|
17 punktów) — poniżej wyłącznie decyzje, które doprowadziły do zmian w
|
||||||
fix-pack 1 (`task/ha-fix-pack-1`) albo świadomie do braku zmian. Reszta
|
fix-pack 1 (`task/ha-fix-pack-1`) albo świadomie do braku zmian. Reszta
|
||||||
checklisty (baterie/re-pairing czujników, kalibracje TRV, xiaomi_miot,
|
checklisty (baterie/re-pairing czujników, kalibracje TRV, xiaomi_miot,
|
||||||
konsolidacja aliasów, higiena 4.x) zostaje otwarta w `docs/backlog.md`.
|
konsolidacja aliasów, higiena 4.x) zostaje otwarta w `kb/phases/backlog.md`.
|
||||||
|
|
||||||
- **Pkt 6 (klima salon: sunset ubija też ręczne chłodzenie?)** — decyzja:
|
- **Pkt 6 (klima salon: sunset ubija też ręczne chłodzenie?)** — decyzja:
|
||||||
NIE. „Klima salon: wyłącz…" (`1784804668795`) ma teraz respektować
|
NIE. „Klima salon: wyłącz…" (`1784804668795`) ma teraz respektować
|
||||||
|
|
@ -166,7 +166,7 @@ konsolidacja aliasów, higiena 4.x) zostaje otwarta w `docs/backlog.md`.
|
||||||
- **Pkt 7 (enforcer sleep mode gasi światła cyklicznie całą noc) i pkt 9
|
- **Pkt 7 (enforcer sleep mode gasi światła cyklicznie całą noc) i pkt 9
|
||||||
(konsolidacja czterech nocnych wyłączników)** — bez zmian w tym fix-packu.
|
(konsolidacja czterech nocnych wyłączników)** — bez zmian w tym fix-packu.
|
||||||
Oba wchłania przyszły projekt „architektura night_mode" (patrz
|
Oba wchłania przyszły projekt „architektura night_mode" (patrz
|
||||||
`docs/backlog.md`) — punktowa łatka tu tylko dodałaby kolejny wariant do
|
`kb/phases/backlog.md`) — punktowa łatka tu tylko dodałaby kolejny wariant do
|
||||||
już przegęszczonego zestawu nakładających się automatyzacji (audyt 2.2).
|
już przegęszczonego zestawu nakładających się automatyzacji (audyt 2.2).
|
||||||
- **Pkt 11 (OwnTracks: przywrócić czy skasować) i pkt 12 (Leave auto on:
|
- **Pkt 11 (OwnTracks: przywrócić czy skasować) i pkt 12 (Leave auto on:
|
||||||
batch 02 — włączyć z powrotem?)** — świadomie bez zmian; obie wymagają
|
batch 02 — włączyć z powrotem?)** — świadomie bez zmian; obie wymagają
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ zdecydować, czy podbić concurrency, czy zostawić zapas na ollama/AI.
|
||||||
rsync/borg → SOLARIA (2 TB, ta sama LAN). Retencja: 7 dziennych +
|
rsync/borg → SOLARIA (2 TB, ta sama LAN). Retencja: 7 dziennych +
|
||||||
4 tygodniowe + 6 miesięcznych. Offsite (np. restic → chmura) zostaje jako
|
4 tygodniowe + 6 miesięcznych. Offsite (np. restic → chmura) zostaje jako
|
||||||
future-note, poza zakresem tego etapu. Cron/skrypt deployowy powstaje przy
|
future-note, poza zakresem tego etapu. Cron/skrypt deployowy powstaje przy
|
||||||
deployu modułu 2, nie teraz. Szczegóły: `services/paperless/README.md`.
|
deployu modułu 2, nie teraz. Szczegóły: `kb/services/paperless.md`.
|
||||||
|
|
||||||
- **4. Redis brokera: `requirepass`.** Broker (6380) dostaje hasło —
|
- **4. Redis brokera: `requirepass`.** Broker (6380) dostaje hasło —
|
||||||
`PAPERLESS_REDIS_PASSWORD` w `.env` po obu stronach (paperless@PIHA,
|
`PAPERLESS_REDIS_PASSWORD` w `.env` po obu stronach (paperless@PIHA,
|
||||||
|
|
@ -76,7 +76,7 @@ zdecydować, czy podbić concurrency, czy zostawić zapas na ollama/AI.
|
||||||
+ SOLARIA po NFS) świadomie zaakceptowane — indeks jest odtwarzalny
|
+ SOLARIA po NFS) świadomie zaakceptowane — indeks jest odtwarzalny
|
||||||
(`document_index reindex`), oryginałom nic nie grozi. Bez zmian w
|
(`document_index reindex`), oryginałom nic nie grozi. Bez zmian w
|
||||||
configu; fallback-worker na PIHA zostaje. Szczegóły:
|
configu; fallback-worker na PIHA zostaje. Szczegóły:
|
||||||
`services/paperless-worker/README.md`.
|
`kb/services/paperless-worker.md`.
|
||||||
|
|
||||||
- **6. Domeny: `kapala.org` (mesh, prywatne).** `paper.kapala.org`
|
- **6. Domeny: `kapala.org` (mesh, prywatne).** `paper.kapala.org`
|
||||||
(Paperless), `cloud.kapala.org` (Nextcloud) — potwierdzone, `*.okit.pl`
|
(Paperless), `cloud.kapala.org` (Nextcloud) — potwierdzone, `*.okit.pl`
|
||||||
|
|
@ -99,7 +99,7 @@ zdecydować, czy podbić concurrency, czy zostawić zapas na ollama/AI.
|
||||||
maintainerów paperless-ngx (nieoficjalnie wspierany): ten sam obraz,
|
maintainerów paperless-ngx (nieoficjalnie wspierany): ten sam obraz,
|
||||||
`command: celery --app paperless worker`, wspólny Redis+Postgres+storage,
|
`command: celery --app paperless worker`, wspólny Redis+Postgres+storage,
|
||||||
identyczne ścieżki kontenerowe i numeryczny UID po obu stronach. Pełny
|
identyczne ścieżki kontenerowe i numeryczny UID po obu stronach. Pełny
|
||||||
wynik badania + ryzyka: `services/paperless-worker/README.md`.
|
wynik badania + ryzyka: `kb/services/paperless-worker.md`.
|
||||||
- Storage dokumentów na PIHA; NFS export → SOLARIA po LAN
|
- Storage dokumentów na PIHA; NFS export → SOLARIA po LAN
|
||||||
(192.168.31.5 → 192.168.31.70), nie Tailscale.
|
(192.168.31.5 → 192.168.31.70), nie Tailscale.
|
||||||
- AOF w Redis brokera (kolejka przeżywa restart — zero utraty zadań).
|
- AOF w Redis brokera (kolejka przeżywa restart — zero utraty zadań).
|
||||||
|
|
|
||||||
27
kb/decisions/kb-log-decyzji.md
Normal file
27
kb/decisions/kb-log-decyzji.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: decision
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-06-26
|
||||||
|
links:
|
||||||
|
- ../subsystems/kb-overview.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# KB — log decyzji (zamkniete vs otwarte)
|
||||||
|
|
||||||
|
## Decyzje — zamknięte vs otwarte
|
||||||
|
|
||||||
|
**Zamknięte:**
|
||||||
|
- Spine: Postgres + pgvector (nie Qdrant).
|
||||||
|
- Embed: **bge-m3** (multilingual, długi kontekst — pod polski lepszy niż multilingual-e5).
|
||||||
|
- Załączniki: indeksowane w **II turze** (MVP najpierw czysty tekst).
|
||||||
|
- Warstwa 3 startuje jako **cienki graf encji**; federacja przy zapytaniu dochodzi później (docelowo hybryda).
|
||||||
|
- Dokumenty: Nextcloud + Paperless-ngx.
|
||||||
|
|
||||||
|
**Otwarte:**
|
||||||
|
- **Transakcje:** agregator vs CSV, pokrycie mBanku, Revolut, koszt (filar #4).
|
||||||
|
- **Maile §design:** sizing archiwum / node (ile waży Gmail), unifikacja adaptera (jeden IMAP dla obu vs JMAP+IMAP osobno).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -29,5 +29,5 @@ widzieć **ten sam Redis, tego samego Postgresa i te same pliki**. Stąd:
|
||||||
restart brokera nie gubi kolejki).
|
restart brokera nie gubi kolejki).
|
||||||
|
|
||||||
Szczegóły NFS (export na PIHA, mount na SOLARIA, ryzyko indeksu Whoosh) —
|
Szczegóły NFS (export na PIHA, mount na SOLARIA, ryzyko indeksu Whoosh) —
|
||||||
`services/paperless-worker/README.md`.
|
`kb/services/paperless-worker.md`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ visibility: private
|
||||||
status: deprecated
|
status: deprecated
|
||||||
updated: 2026-06-24
|
updated: 2026-06-24
|
||||||
links: []
|
links: []
|
||||||
superseded_by: "kb/phases/backlog.md (docs/backlog.md przejal ewidencje dlugu)"
|
superseded_by: "kb/phases/backlog.md (kb/phases/backlog.md przejal ewidencje dlugu)"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Tech Debt
|
# Tech Debt
|
||||||
|
|
|
||||||
28
kb/incidents/2026-07-12-deploy-local-ghost-kontenery.md
Normal file
28
kb/incidents/2026-07-12-deploy-local-ghost-kontenery.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bug: deploy-local.sh control-plane pada na ghost-kontenerach i zostawia mózg rozłożony (2026-07-12)
|
||||||
|
|
||||||
|
**Objaw.** `bash deploy-local.sh` przerwał się w połowie:
|
||||||
|
`Error response from daemon: No such container: 5ee6fec5455d_control-plane-ui` →
|
||||||
|
deploy abort → **ZERO kontenerów control-plane** (`docker ps -a` pusty). Mózg całkowicie
|
||||||
|
down. Zdarzyło się DWA RAZY tego samego dnia. Ratunek: ponowny `deploy-local.sh`
|
||||||
|
(gdy ghost już zniknął, compose stawia czysto).
|
||||||
|
|
||||||
|
**Root cause (podejrzenie).** Ten sam COMPOSE_PROJECT_NAME divergence / ghost
|
||||||
|
hash-prefixed containers, co przy `deploy.sh vps` (naprawione guardem 3b71707).
|
||||||
|
Compose próbuje Recreate kontenera pod nazwą `<hash>_control-plane-ui`, której Docker
|
||||||
|
już nie zna → błąd → `set -e` przerywa deploy w połowie.
|
||||||
|
|
||||||
|
**Fix (DO ZROBIENIA).** deploy-local.sh powinien być odporny: cleanup ghostów przed
|
||||||
|
recreate (`docker compose down --remove-orphans` albo jawne usunięcie hash-prefixed
|
||||||
|
kontenerów), ewentualnie jawny `-p` (COMPOSE_PROJECT_NAME) żeby nazwy były deterministyczne.
|
||||||
|
Deploy mózgu NIE MOŻE zostawiać control-plane w stanie zero-kontenerów.
|
||||||
|
|
||||||
50
kb/incidents/2026-07-12-observer-checkpoint-leksykalny.md
Normal file
50
kb/incidents/2026-07-12-observer-checkpoint-leksykalny.md
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bug: checkpoint observera po ścieżce leksykalnej — kruchy, zatruwa węzeł na zawsze (2026-07-12)
|
||||||
|
|
||||||
|
**Objaw.** PIHA była "martwa" dla observera ~34 dni mimo działającego node-agenta.
|
||||||
|
Eventy dojeżdżały na VPS (7344 plików w /opt/homelab/events/piha/), ale observer
|
||||||
|
ich NIE konsumował — `last_seen` nie drgnął, shadow-read logował
|
||||||
|
`SHADOW_LIVENESS_MISMATCH node=piha event=dead prom=up` z rosnącym wiekiem.
|
||||||
|
|
||||||
|
**Root cause.** `observer_checkpoint.json` trzyma per-węzeł ostatnio przetworzoną
|
||||||
|
ŚCIEŻKĘ i porównuje ją LEKSYKALNIE (stringowo), awansując tylko "do przodu".
|
||||||
|
Checkpoint PIHA utknął na `evt-unknown-1781254800-ha_update_available-homeassistant-951.json`
|
||||||
|
(event z HA, który wpadł do katalogu piha/ z node="unknown"). Nowe eventy nazywają się
|
||||||
|
`evt-piha-<ts>-...`, a leksykalnie **"evt-piha-…" < "evt-unknown-…"** (bo `p` < `u`),
|
||||||
|
więc KAŻDY nowy event był uznawany za starszy niż checkpoint i pomijany.
|
||||||
|
|
||||||
|
**Fix doraźny (zastosowany).** Usunięcie wpisu `piha` z node_checkpoints + restart
|
||||||
|
observera → 7344 eventy przetworzone, `last_seen_age` spadł z 2 082 036 s (~24 dni)
|
||||||
|
do 19 s, status=online/fresh, mismatch zniknął.
|
||||||
|
|
||||||
|
**Fix systemowy (ZROBIONE 2026-07-14, `task/fix-observer-checkpoint`).** Checkpoint
|
||||||
|
per-węzeł trzyma teraz **TIMESTAMP** (int epoch), nie ścieżkę. „Nowy event" =
|
||||||
|
`ts_z_nazwy_pliku > checkpoint_ts_węzła`; kolejność przetwarzania sortowana po
|
||||||
|
timestampie, nie leksykalnie. Timestamp parsowany z nazwy `evt-<node>-<unixts>-…`
|
||||||
|
(regex `-(\d{9,11})-`, ten sam co `operator_ui._event_file_ts`); **fallback na
|
||||||
|
mtime** gdy nazwa nie pasuje — nieparsowalna nazwa NIGDY nie zwraca 0 (0 = leksykalne
|
||||||
|
„starszy niż checkpoint" = dokładnie ten poison). Migracja starych checkpointów
|
||||||
|
(ścieżka→ts) przy starcie; nieparsowalna wartość → 0 (reprocess wszystkiego —
|
||||||
|
bezpieczne, `process_event` jest idempotentne na `last_seen`/`world_state`; lepiej
|
||||||
|
przetworzyć duplikaty niż zgubić węzeł). Testy regresyjne w
|
||||||
|
`test_incident_lifecycle.py` (sekcja 9). Znany, akceptowalny warunek brzegowy:
|
||||||
|
strict `>` może pominąć event o `ts == checkpoint` dostarczony w PÓŹNIEJSZYM cyklu
|
||||||
|
niż inne eventy z tej samej sekundy — nierealne przy cadence shippingu (rsync co
|
||||||
|
60 s wysyła całą partię danej sekundy razem; kolejne partie są ~60 s od siebie).
|
||||||
|
|
||||||
|
**Uwaga do idempotencji (zbadane).** Reprocess tego samego eventu NIE psuje
|
||||||
|
world_state (status/last_seen deterministyczne, resolve incydentu guardowany na
|
||||||
|
`status=="active"`), ALE `_handle_incident`/`deployment_*` inkrementują
|
||||||
|
`occurrence_count` i dopisują do `events[]` przy każdym przetworzeniu — reprocess
|
||||||
|
(np. jednorazowo po migracji) zawyża te liczniki. To kosmetyka, nie korupcja stanu.
|
||||||
|
Docelowo można dedupować po `event.id` w `events[]` — osobny, drobny task.
|
||||||
|
|
||||||
51
kb/incidents/2026-07-12-paperless-worker-config.md
Normal file
51
kb/incidents/2026-07-12-paperless-worker-config.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fix: paperless-worker@SOLARIA — dwa bugi configu, naprawione i zweryfikowane na żywo (2026-07-12)
|
||||||
|
|
||||||
|
**Kontekst.** Moduł 3 (`services/paperless-worker/`, split-host OCR worker) był
|
||||||
|
zdeployowany i brał zadania z kolejki, ale miał dwa bugi w compose:
|
||||||
|
|
||||||
|
1. **`command: celery ...` nie odpalał celery.** Obraz paperless-ngx
|
||||||
|
(`/sbin/docker-entrypoint.sh`) routuje każdy argument NIE zaczynający się
|
||||||
|
od `/` do `manage.py` — więc `celery` lądował jako nieznana subkomenda
|
||||||
|
Django, nie jako program. Fix: `command: /usr/sbin/gosu paperless
|
||||||
|
/usr/local/bin/celery ...` (ścieżka absolutna wchodzi w gałąź `exec "$@"`
|
||||||
|
entrypointu; `gosu paperless` z przodu bo ta gałąź nie dostaje automatycznego
|
||||||
|
gosu, inaczej proces poszedłby jako root i zepsuł właściciela plików na NFS).
|
||||||
|
2. **Brak współdzielonego `SCRATCH_DIR`.** Paperless@PIHA staguje wgrywany
|
||||||
|
plik w `/tmp/paperless` (domyślny `SCRATCH_DIR`) i niesie tę ścieżkę w
|
||||||
|
payloadzie zadania celery jako ścieżkę absolutną. Worker@SOLARIA miał
|
||||||
|
własny, lokalny `/tmp/paperless` — gdy odbierał zadanie zamiast workera
|
||||||
|
PIHA, padał `Cannot consume ...: File not found`. Fix: NFS volume
|
||||||
|
`paperless_scratch` (ten sam wzorzec co `data/media/consume`) na
|
||||||
|
`/opt/homelab/data/paperless/scratch` (już istniał na PIHA, `chown 1000:1000`),
|
||||||
|
mount na `/tmp/paperless` po obu stronach.
|
||||||
|
|
||||||
|
Oba fixy + uzasadnienie: `services/paperless/docker-compose.yml`,
|
||||||
|
`services/paperless-worker/docker-compose.yml`, `kb/services/paperless-worker.md`.
|
||||||
|
Zweryfikowane end-to-end na żywo (branch `task/paperless-worker-fix`, jeszcze
|
||||||
|
niezmergowany do master w momencie pisania tego wpisu): 3 dokumenty testowe
|
||||||
|
wrzucone do `consume/` na PIHA, jeden odebrany i dokończony przez worker@SOLARIA
|
||||||
|
(log: `ocrmypdf`/`tesseract` → `ConsumeTaskPlugin completed with: Success`),
|
||||||
|
zero `File not found`. Dokumenty testowe usunięte po teście (`document.delete()`
|
||||||
|
+ ręczny cleanup plików) — produkcyjne 6 dokumentów nietknięte.
|
||||||
|
|
||||||
|
**Otwarte (świadomie odłożone, nie blokuje działania):**
|
||||||
|
- `hosts/solaria/services.yaml` i `inventory/topology.yaml` nie mają wpisu
|
||||||
|
`paperless-worker` (SOLARIA ma tam tylko `node-agent`) — było zaplanowane w
|
||||||
|
cutover checkliście README jako krok "przy deployu", ale nigdy nie zrobione.
|
||||||
|
Bez tego wpisu supervisor/observer nie widzą tego serwisu w desired-state —
|
||||||
|
drift (np. worker padnie i nie wstanie) nie zostanie automatycznie wykryty
|
||||||
|
przez agent system, tylko przez brak przetwarzania kolejki.
|
||||||
|
- Test formalnego fallbacku (stop worker@SOLARIA → kolejka mieli na PIHA →
|
||||||
|
start → drenaż) nie był wykonany w tej sesji — mechanizm nie zmienił się
|
||||||
|
tym fixem (był już OK), ale warto zweryfikować przy okazji.
|
||||||
|
|
||||||
48
kb/incidents/2026-07-14-ha-diag-agent-node-unknown.md
Normal file
48
kb/incidents/2026-07-14-ha-diag-agent-node-unknown.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bug: ha-diag-agent emituje eventy z node="unknown" do katalogu innego węzła (2026-07-14) — ZROBIONE (2026-07-15, `f2ba81b`)
|
||||||
|
|
||||||
|
**Kontekst.** To był plik-truciciel z buga checkpointu wyżej:
|
||||||
|
`evt-unknown-1781254800-ha_update_available-homeassistant-951.json` w
|
||||||
|
`events/piha/`. Node w evencie = `unknown`, ale plik wylądował w katalogu `piha/`.
|
||||||
|
Sufiks `-951` to `_seq` emittera → agent nachodził długo, wyemitował 951 eventów,
|
||||||
|
wszystkie jako `node="unknown"`.
|
||||||
|
|
||||||
|
**Root cause (config-wiring).** Tożsamość agenta (`node_name`) i KATALOG eventów
|
||||||
|
pochodzą z DWÓCH niezależnych źródeł:
|
||||||
|
- `services/ha-diag-agent/src/ha_diag/config.py:20` → `node_name: str = "unknown"`
|
||||||
|
(domyślne, gdy env `NODE_NAME` nie dotrze do procesu w kontenerze).
|
||||||
|
- `services/ha-diag-agent/docker-compose.yml:12` → wolumen
|
||||||
|
`/opt/homelab/events/${NODE_NAME:-ha-diag}:/events` — `${NODE_NAME}` jest
|
||||||
|
interpolowane po stronie HOSTA (compose), a katalog jest dodatkowo twardo
|
||||||
|
przypięty do `piha` w `hosts/piha/runtime/ha-diag-agent/docker-compose.override.yml`.
|
||||||
|
|
||||||
|
Jeśli `NODE_NAME` trafi do interpolacji wolumenu/override (→ `piha`), ale NIE do
|
||||||
|
`environment:` procesu (albo `Settings.load()` przez `os.environ.setdefault` go nie
|
||||||
|
nadpisze), aplikacja czyta `node_name="unknown"` i pisze eventy `node="unknown"`
|
||||||
|
do katalogu `events/piha/`. Rozjazd między nazwą w evencie a katalogiem docelowym.
|
||||||
|
|
||||||
|
**Skutek.** Poza zatruciem checkpointu (już naprawione osobno): eventy `node="unknown"`
|
||||||
|
są bezużyteczne dla world_state (observer tworzy węzeł-widmo `unknown`, potem prune go
|
||||||
|
kasuje bo nie ma go w topologii) — realny sygnał z ha-diag na piha przepada.
|
||||||
|
|
||||||
|
**Fix — ZROBIONE (2026-07-15, `f2ba81b`, `docs/sessions/2026-07-15.md`).** Wariant (a):
|
||||||
|
`node_name` NIGDY nie może być `"unknown"` w produkcji. `config.py`
|
||||||
|
`Field(default="unknown", validate_default=True)` + validator odrzuca `""`/`"unknown"`;
|
||||||
|
`main.py` → `SystemExit(1)` FATAL przy braku `NODE_NAME`; `EventEmitter.__init__` jako
|
||||||
|
ostatnia bramka przed nazwą pliku eventu. +18 testów, 0 regresji. Zmergowany i
|
||||||
|
zdeployowany na PIHA (rebuild, `NODE_NAME=piha` dochodzi do procesu). Pliki
|
||||||
|
`evt-unknown-*` na VPS/PIHA: 0 (potwierdzone).
|
||||||
|
**Pozostaje osobno (druga warstwa obrony, nadal TODO):** observer/emitter powinien
|
||||||
|
docelowo odrzucać/kwarantannować event, którego `node` w treści != katalog docelowy —
|
||||||
|
dzisiejszy fix zamyka źródło (`unknown` nie powstaje), ale nie waliduje spójności
|
||||||
|
node↔katalog dla innych, przyszłych źródeł eventów.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bug: deploy-node.sh nie przebudowuje obrazu — deploy "OK" ale nowy kod nie wchodzi (2026-07-15) — ✅ ZROBIONE (2026-07-16, commit `77defff`)
|
||||||
|
|
||||||
|
**Objaw.** `deploy-node.sh <serwis>` robi `docker compose up -d` BEZ `--build`. Dla
|
||||||
|
serwisów z Dockerfile (ha-diag-agent, node-agent, llm-gateway, brain-watchdog, itd.),
|
||||||
|
gdy zmienia się TYLKO kod (nie compose/env), compose widzi "kontener działa, obraz ten
|
||||||
|
sam" → status `Running` (0.0s), NIE przebudowuje i NIE recreatuje. Nowy kod z repo NIE
|
||||||
|
wchodzi w życie mimo `git pull` i "Deployment Complete".
|
||||||
|
|
||||||
|
**Skutek — cicha rozbieżność repo↔runtime.** Deploy raportuje sukces, a kontener biega
|
||||||
|
na starym obrazie. Ugryzło DWA razy: fleet-prometheus (config nie wchodził bez
|
||||||
|
force-recreate) i ha-diag-agent 2026-07-15 (fix node_name był w repo `f2ba81b`, ale
|
||||||
|
`Running` zamiast rebuild — trzeba było ręcznego `docker compose up -d --build
|
||||||
|
--force-recreate`).
|
||||||
|
|
||||||
|
**Root cause.** deploy-node.sh (~linia 110) w pętli deployu: brak `--build` w wywołaniu
|
||||||
|
compose. Docker cache'uje obraz po tagu, nie po zawartości src/.
|
||||||
|
compose. Docker cache'uje obraz po tagu, nie po zawartości src/.
|
||||||
|
|
||||||
|
**Fix — ZROBIONE (2026-07-16, `77defff`).** deploy-node.sh wywołuje teraz `--build`
|
||||||
|
warunkowo, gdy serwis ma top-level `Dockerfile` (`test -f services/<svc>/Dockerfile`);
|
||||||
|
prebuilt serwisy bez `--build` (no-op). Zweryfikowane w boju na PIHA: 6 serwisów
|
||||||
|
(node-agent/ha-diag/brain-watchdog/llm-gateway → Building; vikunja/kb-postgres → prebuilt).
|
||||||
|
**Follow-up pozostawiony**: `agent-system` ma build w podkatalogach bez top-level
|
||||||
|
Dockerfile — niezarejestrowany przez tę detekcję, osobny task.
|
||||||
|
|
||||||
40
kb/incidents/2026-07-16-ollama-solaria-brak-sterownika.md
Normal file
40
kb/incidents/2026-07-16-ollama-solaria-brak-sterownika.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ollama SOLARIA: brak sterownika NVIDII — ZAMKNIĘTE (2026-07-16)
|
||||||
|
|
||||||
|
**Kontekst.** Cutover 2026-07-15 (`kb/runbooks/ollama-solaria-cutover.md`)
|
||||||
|
odkrył, że SOLARIA nie miała zainstalowanego żadnego sterownika NVIDII —
|
||||||
|
`nvidia-smi` nie istniał na hoście. `hosts/solaria/services.yaml` opisywał
|
||||||
|
ollama jako "GPU-backed" od dawna, ale to było aspiracyjne — Ollama zawsze
|
||||||
|
szła CPU-only. GPU reservation zakomentowana w
|
||||||
|
`services/ollama/docker-compose.yml` (`f57a01a`); item trafił do backlogu
|
||||||
|
jako blokujący fazę mailową embeddingów (moduł 5).
|
||||||
|
|
||||||
|
**Fix (2026-07-16).** Zainstalowany `nvidia-driver-595-open` z repo dystrybucji
|
||||||
|
(nie stary PPA `graphics-drivers` dla jammy — zdezaktywowany przez rename na
|
||||||
|
`.disabled`). RTX 4070 Ti SUPER 16GB, CUDA 13.2, `nvidia-smi` działa na
|
||||||
|
hoście. `nvidia-container-toolkit` był już obecny (doinstalowany jako
|
||||||
|
prerequisite przy cutoverze 07-15). GPU reservation przywrócona w compose.
|
||||||
|
Pomiar throughput GPU vs CPU baseline (0.79s/chunk) — patrz
|
||||||
|
`kb/phases/kb-m5-documents-ingest-fazy.md`, sekcja timing.
|
||||||
|
|
||||||
|
**Status:** ZAMKNIĘTE.
|
||||||
|
|
||||||
|
**Follow-upy pozostawione (osobne taski):**
|
||||||
|
- **Batching wywołań Ollamy** — przed fazą mailową (225k kopert). Sekwencyjne
|
||||||
|
wywołania `/api/embeddings` (nawet na GPU) będą wąskim gardłem przy takiej
|
||||||
|
skali; ocenić równoległość/batch API Ollamy.
|
||||||
|
- **`UNIQUE(envelope_id, chunk_index)` bez `model`** w `document_chunk`
|
||||||
|
(`services/kb-postgres/init/002_chunks.sql`) — re-embedding innym modelem
|
||||||
|
cicho no-opuje się przez istniejący constraint. Schema change do zrobienia
|
||||||
|
przy fazie 3 (patrz `kb/phases/kb-m5-documents-ingest-fazy.md`, sekcja "Idempotency"
|
||||||
|
kroku 6 embed).
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ followed the move.
|
||||||
**Decision**: 192.168.31.7 (HAOS/RPi4) is canonical `ken`. The piha
|
**Decision**: 192.168.31.7 (HAOS/RPi4) is canonical `ken`. The piha
|
||||||
container is renamed `ken-legacy` in `instances.yaml`, `status: archived`.
|
container is renamed `ken-legacy` in `instances.yaml`, `status: archived`.
|
||||||
Plan: archival import for historical reference → `docker stop` (not `rm`)
|
Plan: archival import for historical reference → `docker stop` (not `rm`)
|
||||||
→ one week of observation → decide on `docker rm`. See `docs/backlog.md`
|
→ one week of observation → decide on `docker rm`. See `kb/phases/backlog.md`
|
||||||
for the ha-diag-agent re-pointing and wind-down follow-ups this incident
|
for the ha-diag-agent re-pointing and wind-down follow-ups this incident
|
||||||
generated.
|
generated.
|
||||||
|
|
||||||
|
|
|
||||||
50
kb/incidents/2026-07-22-ha-ken-cutover-legacy.md
Normal file
50
kb/incidents/2026-07-22-ha-ken-cutover-legacy.md
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../phases/backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cutover HA "ken": kontener piha to legacy, prawdziwy dom to RPi4/HAOS (2026-07-22)
|
||||||
|
|
||||||
|
**Data**: 2026-07-22
|
||||||
|
**Źródło**: recon — dwie instancje HA równolegle sterowały domem (kontener
|
||||||
|
`homeassistant5` na piha + RPi4 HAOS 192.168.31.7), patrz
|
||||||
|
`kb/decisions/ha-configs-as-code.md` sekcja "Incident log". `instances.yaml`
|
||||||
|
naprawiony w tej samej sesji: `ken` = 192.168.31.7 (api), `ken-legacy` =
|
||||||
|
dawny kontener piha (docker-exec, archived).
|
||||||
|
|
||||||
|
**Do zrobienia**:
|
||||||
|
1. **ha-diag-agent na piha**: przepiąć z `http://localhost:8123` (celuje w
|
||||||
|
legacy!) na `http://192.168.31.7:8123` — wymaga nowego tokenu
|
||||||
|
`diag_agent` wystawionego na instancji 31.7 (obecny token jest dla
|
||||||
|
kontenera piha i nie zadziała na nowym targecie).
|
||||||
|
2. **Wygaszenie `homeassistant5`**: import archiwalny do
|
||||||
|
`services/home-assistant/config/ken-legacy/` → `docker stop` (BEZ `rm`)
|
||||||
|
→ 7 dni obserwacji (upewnić się, że nic w domu nie polega na tym
|
||||||
|
kontenerze) → decyzja o `docker rm`.
|
||||||
|
3. ✅ ZROBIONE (2026-07-22) — **Adapter `api` w `import.sh` dla `ken`**:
|
||||||
|
automatyzacje/skrypty/sceny przez `/api/config/<domain>/config/<id>`
|
||||||
|
(REST), dashboardy/area+entity registry/`input_*` helpery przez websocket
|
||||||
|
API (`scripts/ha/lib/ha_api.py`, `ha_ws.py`, `import_api.py`). Pierwszy
|
||||||
|
realny import `ken` zaimportował 118 automatyzacji, 5 skryptów, 3 sceny,
|
||||||
|
7 dashboardów (default + 6 named; jeden zarejestrowany dashboard nigdy
|
||||||
|
nie skonfigurowany — `config_not_found`, odnotowany w raporcie, nie
|
||||||
|
twardy błąd). Pełny import `/config` pozostaje poza zasięgiem (HAOS bez
|
||||||
|
SSH) — patrz DESIGN.md.
|
||||||
|
4. ✅ ZROBIONE (2026-07-22) — **`scripts/ha/deploy.sh`, adapter `api`, zakres
|
||||||
|
automations/scripts/scenes**: drift-check (świeży re-import vs. `HEAD`,
|
||||||
|
dowolna różnica poza plikami z tego deployu = abort z diffem) →
|
||||||
|
walidacja (lokalny sanity check + `check_config` na instancji) → zapis
|
||||||
|
per obiekt (`POST /api/config/<domain>/config/<id>`) → verify (GET +
|
||||||
|
porównanie, bez auto-rollbacku). `--dry-run` zweryfikowany na żywym
|
||||||
|
`ken` (read-only, bez różnic). Testy offline:
|
||||||
|
`scripts/ha/tests/test_deploy_api_offline.sh`. Poza zakresem: dashboardy/
|
||||||
|
helpery (WS, brak mutującej komendy), adapter `docker-exec`, DELETE
|
||||||
|
obiektów usuniętych z repo (tylko ostrzeżenie).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
27
kb/incidents/deploy-sh-vps-niszczy-control-plane.md
Normal file
27
kb/incidents/deploy-sh-vps-niszczy-control-plane.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: incident
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-06-25
|
||||||
|
links:
|
||||||
|
- ../subsystems/deployment.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# ZNANY BUG — `deploy.sh vps` niszczy control-plane (2026-06-25)
|
||||||
|
|
||||||
|
## ⚠️ ZNANY BUG — `deploy.sh vps` niszczy control-plane (2026-06-25)
|
||||||
|
|
||||||
|
`deploy.sh vps` uruchamia `deploy-node.sh` w pętli po wszystkich serwisach VPS, w tym
|
||||||
|
`control-plane`. Pętla używa innego `COMPOSE_PROJECT_NAME` niż `deploy-local.sh`
|
||||||
|
(który uruchamiany jest z `cwd=services/control-plane`). Niezgodność project-name powoduje
|
||||||
|
`Recreate` → `No such container` → `set -e` przerywa pętlę → **observer, supervisor,
|
||||||
|
executor i operator-ui znikają z VPS.**
|
||||||
|
|
||||||
|
**Dopóki bug nie zostanie naprawiony (backlog — Krytyczny):**
|
||||||
|
- Do deployu control-plane używać: `ssh -t vps 'cd ~/homelab-codex-ws && cd services/control-plane && bash deploy-local.sh'`
|
||||||
|
- Inne serwisy VPS deployować punktowo: `deploy-node.sh` z `--service <name>` lub przez SSH + `docker compose up -d`
|
||||||
|
- **NIE uruchamiać `deploy.sh vps` bez pełnej świadomości ryzyka.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
71
kb/phases/backlog.md
Normal file
71
kb/phases/backlog.md
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: phase
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- ../decisions/backlog-m1-solaria-prune-mitigation.md
|
||||||
|
- ../decisions/backlog-deploy-runner-instalacja.md
|
||||||
|
- ../decisions/backlog-disk-cleanup-zepsuty.md
|
||||||
|
- ../decisions/backlog-deploy-host-pusty.md
|
||||||
|
- ../incidents/2026-07-22-ha-ken-cutover-legacy.md
|
||||||
|
- ha-configs-as-code.md
|
||||||
|
- monitoring-floty-prometheus.md
|
||||||
|
- ../decisions/backlog-aktywne.md
|
||||||
|
- ../decisions/backlog-zamkniete.md
|
||||||
|
- ../decisions/backlog-anomaly-detection-liveness.md
|
||||||
|
- ../decisions/backlog-rozjazdy-repo-rzeczywistosc.md
|
||||||
|
- ../decisions/backlog-uid-gid-flota.md
|
||||||
|
- ../incidents/2026-07-12-observer-checkpoint-leksykalny.md
|
||||||
|
- ../incidents/2026-07-14-ha-diag-agent-node-unknown.md
|
||||||
|
- ../incidents/2026-07-12-deploy-local-ghost-kontenery.md
|
||||||
|
- ../incidents/2026-07-12-paperless-worker-config.md
|
||||||
|
- ../decisions/backlog-kb-serwisy-poza-monitoringiem.md
|
||||||
|
- ../incidents/2026-07-15-deploy-node-nie-przebudowuje-obrazu.md
|
||||||
|
- ../incidents/2026-07-16-ollama-solaria-brak-sterownika.md
|
||||||
|
- ../decisions/backlog-followupy-etap0.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tech-debt backlog
|
||||||
|
|
||||||
|
Centralny tracker tech-długu i znanych usterek. Wpisy ze sesji — dodawaj z datą i kontekstem.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## Spis rozbitych elementow
|
||||||
|
|
||||||
|
> Ten plik byl monolitem 72 KB mieszajacym cztery typy OKF. W etapie 2
|
||||||
|
> zostal rozbity per typ; ponizej spis powstalych dokumentow. Tresc
|
||||||
|
> pozycji nie byla redagowana — kazda sekcja `##` trafila do wlasnego
|
||||||
|
> pliku w calosci.
|
||||||
|
|
||||||
|
### Decyzje / pozycje backlogu
|
||||||
|
|
||||||
|
- [M1 aktywna na SOLARII — cleanup node-agenta wyłączony do czasu R1 (2026-08-04)](../decisions/backlog-m1-solaria-prune-mitigation.md)
|
||||||
|
- [deploy-runner: instalacja na węzłach + E2E redeployu (2026-08-03)](../decisions/backlog-deploy-runner-instalacja.md)
|
||||||
|
- [disk_cleanup w executorze jest zepsuty tak samo jak był redeploy (2026-08-03)](../decisions/backlog-disk-cleanup-zepsuty.md)
|
||||||
|
- [`scripts/deploy/deploy-host.sh` to pusty plik (2026-08-03)](../decisions/backlog-deploy-host-pusty.md)
|
||||||
|
- [Aktywne](../decisions/backlog-aktywne.md)
|
||||||
|
- [Zamknięte](../decisions/backlog-zamkniete.md)
|
||||||
|
- [Anomaly detection liveness — mózg uczy się wzorca dobowego per node (pomysł 2026-06-26)](../decisions/backlog-anomaly-detection-liveness.md)
|
||||||
|
- [Rozjazdy repo<->rzeczywistosc (z inwentaryzacji 2026-06-30)](../decisions/backlog-rozjazdy-repo-rzeczywistosc.md)
|
||||||
|
- [Tech-debt: globalny porządek uid/gid/uprawnień we flocie (2026-07-10)](../decisions/backlog-uid-gid-flota.md)
|
||||||
|
- [Nowe serwisy KB nie sa w monitoringu (desired-state)](../decisions/backlog-kb-serwisy-poza-monitoringiem.md)
|
||||||
|
- [Follow-upy z etapu 0 (truth cleanup, 2026-07-29)](../decisions/backlog-followupy-etap0.md)
|
||||||
|
|
||||||
|
### Incydenty
|
||||||
|
|
||||||
|
- [Cutover HA "ken": kontener piha to legacy, prawdziwy dom to RPi4/HAOS (2026-07-22)](../incidents/2026-07-22-ha-ken-cutover-legacy.md)
|
||||||
|
- [Bug: checkpoint observera po ścieżce leksykalnej — kruchy, zatruwa węzeł na zawsze (2026-07-12)](../incidents/2026-07-12-observer-checkpoint-leksykalny.md)
|
||||||
|
- [Bug: ha-diag-agent emituje eventy z node="unknown" do katalogu innego węzła (2026-07-14) — ZROBIONE (2026-07-15, `f2ba81b`)](../incidents/2026-07-14-ha-diag-agent-node-unknown.md)
|
||||||
|
- [Bug: deploy-local.sh control-plane pada na ghost-kontenerach i zostawia mózg rozłożony (2026-07-12)](../incidents/2026-07-12-deploy-local-ghost-kontenery.md)
|
||||||
|
- [Fix: paperless-worker@SOLARIA — dwa bugi configu, naprawione i zweryfikowane na żywo (2026-07-12)](../incidents/2026-07-12-paperless-worker-config.md)
|
||||||
|
- [Bug: deploy-node.sh nie przebudowuje obrazu — deploy "OK" ale nowy kod nie wchodzi (2026-07-15) — ✅ ZROBIONE (2026-07-16, commit `77defff`)](../incidents/2026-07-15-deploy-node-nie-przebudowuje-obrazu.md)
|
||||||
|
- [Ollama SOLARIA: brak sterownika NVIDII — ZAMKNIĘTE (2026-07-16)](../incidents/2026-07-16-ollama-solaria-brak-sterownika.md)
|
||||||
|
|
||||||
|
### Fazy
|
||||||
|
|
||||||
|
- [Nowy podprojekt: Home Assistant configs-as-code (szkielet)](ha-configs-as-code.md)
|
||||||
|
- [Plan: Monitoring floty — Prometheus jako źródło prawdy](monitoring-floty-prometheus.md)
|
||||||
23
kb/phases/ha-configs-as-code.md
Normal file
23
kb/phases/ha-configs-as-code.md
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: phase
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nowy podprojekt: Home Assistant configs-as-code (szkielet)
|
||||||
|
|
||||||
|
**Data**: 2026-07-21
|
||||||
|
**Branch**: `task/ha-skeleton`
|
||||||
|
|
||||||
|
Szkielet struktury dla `services/home-assistant/` — configs-as-code dla
|
||||||
|
instancji HA (`ken` na PIHA, `chelsty-ha`). Na razie tylko struktura +
|
||||||
|
read-only import (`scripts/ha/import.sh`), bez deployu. Fazowanie, wybór
|
||||||
|
adaptera per instancja, model sync i otwarte pytania —
|
||||||
|
`kb/decisions/ha-configs-as-code.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -15,7 +15,7 @@ links: []
|
||||||
## STATUS: prerekwizyt RAM SPELNIONY (2026-07-02)
|
## STATUS: prerekwizyt RAM SPELNIONY (2026-07-02)
|
||||||
|
|
||||||
Faza 1 (audyt read-only) + faza 2 (egzekucja po review Oskara) wykonane —
|
Faza 1 (audyt read-only) + faza 2 (egzekucja po review Oskara) wykonane —
|
||||||
szczegoly: `docs/infra/piha-slim-audit-2026-07-02.md` (sekcja "Korekta po review
|
szczegoly: `kb/audits/piha-slim-2026-07-02.md` (sekcja "Korekta po review
|
||||||
+ egzekucja").
|
+ egzekucja").
|
||||||
|
|
||||||
- **Kryterium >= 1.5Gi available: SPELNIONE.** Przed egzekucja: 2.8Gi available
|
- **Kryterium >= 1.5Gi available: SPELNIONE.** Przed egzekucja: 2.8Gi available
|
||||||
|
|
@ -37,7 +37,7 @@ Zwolnic RAM na PIHA (dzis: 3.1Gi available, swap 2G uzyty) tak, by lekki Paperle
|
||||||
serwis wszedl z zapasem, nie na styku swap.
|
serwis wszedl z zapasem, nie na styku swap.
|
||||||
|
|
||||||
## Wymogi
|
## Wymogi
|
||||||
- Audyt 33 shadow-kontenerow (lista w `docs/infra/inventory-2026-06-30.md`).
|
- Audyt 33 shadow-kontenerow (lista w `kb/subsystems/fleet-inventory.md`).
|
||||||
- Zidentyfikowac kandydatow do usuniecia/przeniesienia/wylaczenia:
|
- Zidentyfikowac kandydatow do usuniecia/przeniesienia/wylaczenia:
|
||||||
- **elasticsearch 1Gi** — kto tego uzywa? (wikijs? diskover?) — jesli martwy, ubic
|
- **elasticsearch 1Gi** — kto tego uzywa? (wikijs? diskover?) — jesli martwy, ubic
|
||||||
- **diskover** — jednorazowy indekser? czy chodzi ciagle bez potrzeby?
|
- **diskover** — jednorazowy indekser? czy chodzi ciagle bez potrzeby?
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ links:
|
||||||
|
|
||||||
## Phase 2 — `documents-ingest-paperless` (Paperless -> envelope adapter)
|
## Phase 2 — `documents-ingest-paperless` (Paperless -> envelope adapter)
|
||||||
|
|
||||||
Module 5, phase 2 (`docs/kb/modules/05-faza2-plan.md`, §4.2-4.3, §6 step 5).
|
Module 5, phase 2 (`kb/phases/kb-m5-faza2.md`, §4.2-4.3, §6 step 5).
|
||||||
Reads documents from the **Paperless REST API** (read-only — GET only, never
|
Reads documents from the **Paperless REST API** (read-only — GET only, never
|
||||||
writes to Paperless) and inserts them as `source='paperless'` rows into the
|
writes to Paperless) and inserts them as `source='paperless'` rows into the
|
||||||
`envelope` table on kb-postgres, reusing `kb_mail.envelope.Envelope` /
|
`envelope` table on kb-postgres, reusing `kb_mail.envelope.Envelope` /
|
||||||
|
|
@ -133,7 +133,7 @@ this commit.
|
||||||
|
|
||||||
## Phase 2 step 6 — `documents-ingest-embed` (chunk + embed)
|
## Phase 2 step 6 — `documents-ingest-embed` (chunk + embed)
|
||||||
|
|
||||||
Module 5, phase 2, plan step 6 (`docs/kb/modules/05-faza2-plan.md`, §6 step 6,
|
Module 5, phase 2, plan step 6 (`kb/phases/kb-m5-faza2.md`, §6 step 6,
|
||||||
§2 decision 3). Reads `entities[type=content].text` off every `source='paperless'`
|
§2 decision 3). Reads `entities[type=content].text` off every `source='paperless'`
|
||||||
envelope, chunks it, calls Ollama (`POST /api/embeddings`, model `bge-m3`) for
|
envelope, chunks it, calls Ollama (`POST /api/embeddings`, model `bge-m3`) for
|
||||||
each chunk, and inserts the result into `document_chunk`
|
each chunk, and inserts the result into `document_chunk`
|
||||||
|
|
@ -311,7 +311,7 @@ kb-postgres@PIHA:
|
||||||
|
|
||||||
## Phase 3 step 4 — retrieval cascade (`documents_ingest.retrieval`) + quality gate
|
## Phase 3 step 4 — retrieval cascade (`documents_ingest.retrieval`) + quality gate
|
||||||
|
|
||||||
Module 5, phase 3, plan step 4 (`docs/kb/modules/05-faza3-plan.md`, §6). Two retrieval
|
Module 5, phase 3, plan step 4 (`kb/phases/kb-m5-faza3.md`, §6). Two retrieval
|
||||||
paths, both `query_text -> chunk hits (dist, source)` — the intended clean API surface for
|
paths, both `query_text -> chunk hits (dist, source)` — the intended clean API surface for
|
||||||
phase 4's kb-query, not just this eval:
|
phase 4's kb-query, not just this eval:
|
||||||
|
|
||||||
|
|
@ -328,7 +328,7 @@ phase 4's kb-query, not just this eval:
|
||||||
### Quality gate
|
### Quality gate
|
||||||
|
|
||||||
`eval/queries.yaml` — 7 queries transcribed 1:1 from the phase-2 pilot baseline
|
`eval/queries.yaml` — 7 queries transcribed 1:1 from the phase-2 pilot baseline
|
||||||
(`docs/kb/eval/retrieval-pilot-2026-07-16.md`, left untouched — this is its versioned working
|
(`kb/phases/kb-m5-eval-retrieval-pilot.md`, left untouched — this is its versioned working
|
||||||
copy) with expected envelope / kind (`hit`, `grey_zone`, `negative_control`,
|
copy) with expected envelope / kind (`hit`, `grey_zone`, `negative_control`,
|
||||||
`negative_control_borderline`) per query.
|
`negative_control_borderline`) per query.
|
||||||
|
|
||||||
|
|
@ -373,7 +373,7 @@ short-circuit (stage 2 never queried), and both query entry points embedding exa
|
||||||
|
|
||||||
## Phase 3 step 5 — cyclic ingest (`documents-ingest-cyclic`) + systemd timer
|
## Phase 3 step 5 — cyclic ingest (`documents-ingest-cyclic`) + systemd timer
|
||||||
|
|
||||||
Module 5, phase 3, plan step 5 (`docs/kb/modules/05-faza3-plan.md`, §7). Orchestrates one
|
Module 5, phase 3, plan step 5 (`kb/phases/kb-m5-faza3.md`, §7). Orchestrates one
|
||||||
run of the recurring ingest pipeline: `paperless_adapter.run()` (new `source='paperless'`
|
run of the recurring ingest pipeline: `paperless_adapter.run()` (new `source='paperless'`
|
||||||
envelopes) → `chunk_embed.run()` (new `document_chunk` rows) →
|
envelopes) → `chunk_embed.run()` (new `document_chunk` rows) →
|
||||||
`summarize.run_summarize(backend='anthropic')` (new `document_summary` rows,
|
`summarize.run_summarize(backend='anthropic')` (new `document_summary` rows,
|
||||||
|
|
|
||||||
|
|
@ -545,7 +545,7 @@ zeby dalo sie uruchomic partiami i zweryfikowac progres bez czekania na cale 225
|
||||||
rzedu dziesiatek-set chunkow/s. Caly pilot (2–3k chunkow) → **rzedu minut**, nie wymaga
|
rzedu dziesiatek-set chunkow/s. Caly pilot (2–3k chunkow) → **rzedu minut**, nie wymaga
|
||||||
specjalnego batchowania/partii.
|
specjalnego batchowania/partii.
|
||||||
- **Skala docelowa (70k zalacznikow z maili)**: modul 5 faza-1 to swiadomie **probka, nie
|
- **Skala docelowa (70k zalacznikow z maili)**: modul 5 faza-1 to swiadomie **probka, nie
|
||||||
bulk** (`jobs/documents-ingest/README.md` — decyzja architektoniczna). Realny wolumen
|
bulk** (`kb/phases/kb-m5-documents-ingest-fazy.md` — decyzja architektoniczna). Realny wolumen
|
||||||
ktory trafi do embeddingu zalezy od (a) throughput OCR-workera na SOLARII (modul 3) —
|
ktory trafi do embeddingu zalezy od (a) throughput OCR-workera na SOLARII (modul 3) —
|
||||||
**to jest waskie gardlo skalowania, nie embedding** — oraz (b) filtra selektywnosci
|
**to jest waskie gardlo skalowania, nie embedding** — oraz (b) filtra selektywnosci
|
||||||
(decyzja #6). Sam embedding bge-m3 nie bedzie bottleneckiem nawet przy tysiacach
|
(decyzja #6). Sam embedding bge-m3 nie bedzie bottleneckiem nawet przy tysiacach
|
||||||
|
|
|
||||||
|
|
@ -505,7 +505,7 @@ aktywnych chunków, N większe niż liczba kopert, no-summaries short-circuit)
|
||||||
pakietu przechodzi.
|
pakietu przechodzi.
|
||||||
|
|
||||||
**Eval-set utrwalony**: `jobs/documents-ingest/eval/queries.yaml` (7 zapytań z pilota
|
**Eval-set utrwalony**: `jobs/documents-ingest/eval/queries.yaml` (7 zapytań z pilota
|
||||||
07-16, 1:1 z `docs/kb/eval/retrieval-pilot-2026-07-16.md`, ten plik pozostał nietknięty —
|
07-16, 1:1 z `kb/phases/kb-m5-eval-retrieval-pilot.md`, ten plik pozostał nietknięty —
|
||||||
`queries.yaml` to jego wersjonowana kopia robocza). Skrypt bramki (read-only, integracyjny,
|
`queries.yaml` to jego wersjonowana kopia robocza). Skrypt bramki (read-only, integracyjny,
|
||||||
**nie wchodzi do pytest**): `jobs/documents-ingest/eval/retrieval_eval.py`.
|
**nie wchodzi do pytest**): `jobs/documents-ingest/eval/retrieval_eval.py`.
|
||||||
|
|
||||||
|
|
@ -700,7 +700,7 @@ streszczeń). Kandydaci na pierwsze strony (encje z pilota): PZU/WARTA (polisy),
|
||||||
## 9. Poza zakresem fazy 3
|
## 9. Poza zakresem fazy 3
|
||||||
|
|
||||||
Granice planu — wszystko poniżej jest świadomie odłożone, z istniejącym miejscem w
|
Granice planu — wszystko poniżej jest świadomie odłożone, z istniejącym miejscem w
|
||||||
roadmapie (`docs/kb/kb-00-overview.md` „Stan etapów/Backlog", sesja
|
roadmapie (`kb/subsystems/kb-overview.md` „Stan etapów/Backlog", sesja
|
||||||
`docs/sessions/2026-07-16.md`, backlog operatora):
|
`docs/sessions/2026-07-16.md`, backlog operatora):
|
||||||
|
|
||||||
| Temat | Gdzie zakotwiczone | Kiedy |
|
| Temat | Gdzie zakotwiczone | Kiedy |
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,10 @@ zegarem, master trzyma to samo wewnątrz `EmbedRouter` (też injektowalny zegar)
|
||||||
| `services/kb-query/{README,env.example,service.yaml,docker-compose.yml}` | ~±58 | duplikat | **porzuć** | inny (porzucony) schemat env `OLLAMA_PIHA_URL`; master bogatszy (testy A/B/C, rename `OLLAMA_URL`→`EMBED_PRIMARY_URL`) |
|
| `services/kb-query/{README,env.example,service.yaml,docker-compose.yml}` | ~±58 | duplikat | **porzuć** | inny (porzucony) schemat env `OLLAMA_PIHA_URL`; master bogatszy (testy A/B/C, rename `OLLAMA_URL`→`EMBED_PRIMARY_URL`) |
|
||||||
| `packages/kb-retrieval/src/kb_retrieval/embed.py` (`timeout_s` w `embed_chunk`) | +16 | duplikat funkcji | **porzuć** | master osiąga twardy timeout przez `asyncio.wait_for` bez zmiany współdzielonego pakietu — mniejsza powierzchnia zmian, ten sam efekt |
|
| `packages/kb-retrieval/src/kb_retrieval/embed.py` (`timeout_s` w `embed_chunk`) | +16 | duplikat funkcji | **porzuć** | master osiąga twardy timeout przez `asyncio.wait_for` bez zmiany współdzielonego pakietu — mniejsza powierzchnia zmian, ten sam efekt |
|
||||||
| `jobs/documents-ingest/eval/retrieval_eval.py` (`--transport {direct,http}` + `--base-url`) | +109 | **unikalna wartość** | **cherry-pick** | plan §2 decyzja 6 / §9 (bramka HTTP-equivalence) — **na masterze w ogóle nie istnieje**; e7625cd nie tknął tego pliku, patch aplikuje się czysto; kod woła tylko `GET /search` i czyta `envelope_id`/`dist`/`source` — w pełni zgodny z odpowiedzią mastera |
|
| `jobs/documents-ingest/eval/retrieval_eval.py` (`--transport {direct,http}` + `--base-url`) | +109 | **unikalna wartość** | **cherry-pick** | plan §2 decyzja 6 / §9 (bramka HTTP-equivalence) — **na masterze w ogóle nie istnieje**; e7625cd nie tknął tego pliku, patch aplikuje się czysto; kod woła tylko `GET /search` i czyta `envelope_id`/`dist`/`source` — w pełni zgodny z odpowiedzią mastera |
|
||||||
| `jobs/documents-ingest/README.md` | +6 | **unikalna wartość** | **cherry-pick** | dokumentacja powyższego, idzie w parze |
|
| `kb/phases/kb-m5-documents-ingest-fazy.md` | +6 | **unikalna wartość** | **cherry-pick** | dokumentacja powyższego, idzie w parze |
|
||||||
| `docs/sessions/2026-07-27-kb-f4-fallback.md` | +189 | **unikalna wartość** | **adaptuj** | jedyny zapis: (1) znalezisko osieroconego natywnego `ollama.service` na PIHA + jego wyłączenie 2026-07-27 i backlog odinstalowania, (2) kalibracja live ollama-piha (GO: peak ~983 MiB, ~4.2–5.3 s/embed), (3) metodologia i wyniki bramki §9 (HTTP-equivalence 0 rozbieżności; sol-down Δ~3e-4), (4) rsync-deploy → dirty working tree na PIHA. Wciągnąć z dopiskiem redakcyjnym, że zmergowana implementacja to **inny kod** (e7625cd) i wyniki bramki wymagają powtórki |
|
| `docs/sessions/2026-07-27-kb-f4-fallback.md` | +189 | **unikalna wartość** | **adaptuj** | jedyny zapis: (1) znalezisko osieroconego natywnego `ollama.service` na PIHA + jego wyłączenie 2026-07-27 i backlog odinstalowania, (2) kalibracja live ollama-piha (GO: peak ~983 MiB, ~4.2–5.3 s/embed), (3) metodologia i wyniki bramki §9 (HTTP-equivalence 0 rozbieżności; sol-down Δ~3e-4), (4) rsync-deploy → dirty working tree na PIHA. Wciągnąć z dopiskiem redakcyjnym, że zmergowana implementacja to **inny kod** (e7625cd) i wyniki bramki wymagają powtórki |
|
||||||
| `services/ollama-piha/*` (5 plików) | +155 | duplikat | **porzuć** | wersja mastera lepsza: named volume `ollama_piha_models` (uzasadnienie uid-pattern PIHA), healthcheck sprawdza obecność `bge-m3`, bind tylko 127.0.0.1+LAN |
|
| `services/ollama-piha/*` (5 plików) | +155 | duplikat | **porzuć** | wersja mastera lepsza: named volume `ollama_piha_models` (uzasadnienie uid-pattern PIHA), healthcheck sprawdza obecność `bge-m3`, bind tylko 127.0.0.1+LAN |
|
||||||
| `hosts/piha/runtime/ollama-piha/docker-compose.override.yml` | +13 | duplikat + **1 unikalny fakt** | **adaptuj (mikro)** | ten sam `mem_limit: 2560m`; ale komentarz brancha zawiera potwierdzony pomiar (peak ~983 MiB), a master wciąż mówi „Confirm/trim after live calibration" — dopisać wynik kalibracji do komentarza override'u i/lub sekcji „Calibration" w `services/ollama-piha/README.md` |
|
| `hosts/piha/runtime/ollama-piha/docker-compose.override.yml` | +13 | duplikat + **1 unikalny fakt** | **adaptuj (mikro)** | ten sam `mem_limit: 2560m`; ale komentarz brancha zawiera potwierdzony pomiar (peak ~983 MiB), a master wciąż mówi „Confirm/trim after live calibration" — dopisać wynik kalibracji do komentarza override'u i/lub sekcji „Calibration" w `kb/services/ollama-piha.md` |
|
||||||
| `hosts/piha/services.yaml` | ±26 | duplikat | **porzuć** | master ma własny wpis `ollama-piha` + soft-dependency kb-query; drobna różnica (`offline_required: true` na branchu vs `false` na masterze) — master źródłem prawdy |
|
| `hosts/piha/services.yaml` | ±26 | duplikat | **porzuć** | master ma własny wpis `ollama-piha` + soft-dependency kb-query; drobna różnica (`offline_required: true` na branchu vs `false` na masterze) — master źródłem prawdy |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -107,7 +107,7 @@ skonfigurowanego → `EmbedBackendError`, `fallback_status` (up/unconfigured), s
|
||||||
## 4. Rekomendacja zbiorcza (lista do zatwierdzenia)
|
## 4. Rekomendacja zbiorcza (lista do zatwierdzenia)
|
||||||
|
|
||||||
1. **S1 — cherry-pick**: `retrieval_eval.py --transport http --base-url` + akapit w
|
1. **S1 — cherry-pick**: `retrieval_eval.py --transport http --base-url` + akapit w
|
||||||
`jobs/documents-ingest/README.md` (plan §2 D6/§9; aplikuje się czysto, zero zależności
|
`kb/phases/kb-m5-documents-ingest-fazy.md` (plan §2 D6/§9; aplikuje się czysto, zero zależności
|
||||||
od porzuconego kodu brancha).
|
od porzuconego kodu brancha).
|
||||||
2. **S2 — adaptuj**: `docs/sessions/2026-07-27-kb-f4-fallback.md` → `docs/sessions/`
|
2. **S2 — adaptuj**: `docs/sessions/2026-07-27-kb-f4-fallback.md` → `docs/sessions/`
|
||||||
z dopiskiem redakcyjnym na górze (implementacja z tej sesji porzucona na rzecz
|
z dopiskiem redakcyjnym na górze (implementacja z tej sesji porzucona na rzecz
|
||||||
|
|
@ -116,7 +116,7 @@ skonfigurowanego → `EmbedBackendError`, `fallback_status` (up/unconfigured), s
|
||||||
3. **S3 — adaptuj**: luki testowe T1 + T2 (T3 opcjonalnie) do `test_embed_router.py`.
|
3. **S3 — adaptuj**: luki testowe T1 + T2 (T3 opcjonalnie) do `test_embed_router.py`.
|
||||||
4. **S4 — adaptuj (mikro)**: wynik kalibracji 2026-07-27 (peak ~983 MiB, ~4.2–5.3 s,
|
4. **S4 — adaptuj (mikro)**: wynik kalibracji 2026-07-27 (peak ~983 MiB, ~4.2–5.3 s,
|
||||||
werdykt GO) do komentarza `hosts/piha/runtime/ollama-piha/docker-compose.override.yml`
|
werdykt GO) do komentarza `hosts/piha/runtime/ollama-piha/docker-compose.override.yml`
|
||||||
i sekcji Calibration w `services/ollama-piha/README.md` — pomiar dotyczył kontenera
|
i sekcji Calibration w `kb/services/ollama-piha.md` — pomiar dotyczył kontenera
|
||||||
ollama-piha (ta sama konfiguracja: obraz, `OLLAMA_KEEP_ALIVE=0`, `mem_limit 2560m`),
|
ollama-piha (ta sama konfiguracja: obraz, `OLLAMA_KEEP_ALIVE=0`, `mem_limit 2560m`),
|
||||||
więc **przenosi się** na wersję mastera; różni się tylko storage (bind vs named
|
więc **przenosi się** na wersję mastera; różni się tylko storage (bind vs named
|
||||||
volume), co nie wpływa na RAM/latencję.
|
volume), co nie wpływa na RAM/latencję.
|
||||||
|
|
@ -130,7 +130,7 @@ skonfigurowanego → `EmbedBackendError`, `fallback_status` (up/unconfigured), s
|
||||||
(3d4ee38) i worktree `~/homelab-codex-ws-kb-f4-fallback` po zakończeniu salvage.
|
(3d4ee38) i worktree `~/homelab-codex-ws-kb-f4-fallback` po zakończeniu salvage.
|
||||||
- **(b) Powtórka testu sol-down na żywym masterze**: kalibracja i bramka z 2026-07-27
|
- **(b) Powtórka testu sol-down na żywym masterze**: kalibracja i bramka z 2026-07-27
|
||||||
dotyczyły **innego kodu** (`fallback.py`, env `OLLAMA_PIHA_URL`) — na wdrożonym
|
dotyczyły **innego kodu** (`fallback.py`, env `OLLAMA_PIHA_URL`) — na wdrożonym
|
||||||
e7625cd trzeba przejść testy A/B/C z `services/kb-query/README.md` oraz bramkę
|
e7625cd trzeba przejść testy A/B/C z `kb/services/kb-query.md` oraz bramkę
|
||||||
`retrieval_eval.py --transport http` (po S1): HTTP-equivalence przy SOLARIA-up
|
`retrieval_eval.py --transport http` (po S1): HTTP-equivalence przy SOLARIA-up
|
||||||
(identyczne `dist`) i sol-down (Δ≤epsilon, kolejność top-k identyczna; baseline
|
(identyczne `dist`) i sol-down (Δ≤epsilon, kolejność top-k identyczna; baseline
|
||||||
z 27.07: Δ~3e-4). Symulacja wg README: `EMBED_PRIMARY_URL=http://192.0.2.1:11434`
|
z 27.07: Δ~3e-4). Symulacja wg README: `EMBED_PRIMARY_URL=http://192.0.2.1:11434`
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ links: []
|
||||||
|
|
||||||
### 1.3 PIHA — budżet RAM (istotne dla decyzji D2 / lokalnego fallbacku)
|
### 1.3 PIHA — budżet RAM (istotne dla decyzji D2 / lokalnego fallbacku)
|
||||||
|
|
||||||
- Audyt `docs/infra/piha-slim-audit-2026-07-02.md`: po "bezpiecznym usuń"
|
- Audyt `kb/audits/piha-slim-2026-07-02.md`: po "bezpiecznym usuń"
|
||||||
(elasticsearch+diskover+stary llm-gateway) available rosło z **2.9Gi do ~3.8Gi**
|
(elasticsearch+diskover+stary llm-gateway) available rosło z **2.9Gi do ~3.8Gi**
|
||||||
(na 8 GB total, +4 GB swap). To jest **jedyna zweryfikowana liczba w repo i ma
|
(na 8 GB total, +4 GB swap). To jest **jedyna zweryfikowana liczba w repo i ma
|
||||||
3 tygodnie** — od tego dnia na PIHA doszły (GitOps, z `mem_limit`): paperless+db+broker
|
3 tygodnie** — od tego dnia na PIHA doszły (GitOps, z `mem_limit`): paperless+db+broker
|
||||||
|
|
@ -97,7 +97,7 @@ domeny `*.kapala.org`:
|
||||||
(cert #51 *.okit.pl, cert osobny dla *.kapala.org — sesje ją tylko konfigurują
|
(cert #51 *.okit.pl, cert osobny dla *.kapala.org — sesje ją tylko konfigurują
|
||||||
ręcznie/SQL-em, nigdy nie deployują z repo). kb-query dogania się do tego samego
|
ręcznie/SQL-em, nigdy nie deployują z repo). kb-query dogania się do tego samego
|
||||||
wzorca: nowy vhost w `npm@PIHA`, TLS z **już istniejącego** wildcard `*.kapala.org`
|
wzorca: nowy vhost w `npm@PIHA`, TLS z **już istniejącego** wildcard `*.kapala.org`
|
||||||
(pokrywa `paper.`/`cloud.`/`vikunja.kapala.org` — `docs/kb/modules/DECYZJE-do-podjecia.md`
|
(pokrywa `paper.`/`cloud.`/`vikunja.kapala.org` — `kb/decisions/kb-dokumenty-otwarte.md`
|
||||||
#6) — **żaden nowy certyfikat nie jest potrzebny**.
|
#6) — **żaden nowy certyfikat nie jest potrzebny**.
|
||||||
- **DNS — dwie warstwy, obie trzeba dotknąć** (lekcja `okit-cloudflare-migracja.md`
|
- **DNS — dwie warstwy, obie trzeba dotknąć** (lekcja `okit-cloudflare-migracja.md`
|
||||||
§"WAZNE: split-horizon DNS"): (a) Cloudflare rekord A → Tailscale IP PIHA
|
§"WAZNE: split-horizon DNS"): (a) Cloudflare rekord A → Tailscale IP PIHA
|
||||||
|
|
@ -261,7 +261,7 @@ przed backfillem" z fazy 3 §3.1 (zmierz, obejrzyj, dopiero wtedy zaufaj progowi
|
||||||
### Decyzja 3 — Linki do źródeł: paperless vs gmail
|
### Decyzja 3 — Linki do źródeł: paperless vs gmail
|
||||||
|
|
||||||
**Paperless**: URL do dokumentu — **do zweryfikowania na żywym Paperless przed
|
**Paperless**: URL do dokumentu — **do zweryfikowania na żywym Paperless przed
|
||||||
implementacją** (repo nie ma zapisanego przykładu, `docs/kb/modules/02-paperless-service.md`
|
implementacją** (repo nie ma zapisanego przykładu, `kb/phases/kb-m2-paperless.md`
|
||||||
dokumentuje tylko subdomenę, nie ścieżkę). Kandydat wg konwencji paperless-ngx UI:
|
dokumentuje tylko subdomenę, nie ścieżkę). Kandydat wg konwencji paperless-ngx UI:
|
||||||
`https://paper.kapala.org/documents/<id>/details` (Angular routing) — `envelope_id`
|
`https://paper.kapala.org/documents/<id>/details` (Angular routing) — `envelope_id`
|
||||||
`paperless:<id>` już niesie surowy `<id>` do wstawienia. Krok implementacji: jeden
|
`paperless:<id>` już niesie surowy `<id>` do wstawienia. Krok implementacji: jeden
|
||||||
|
|
@ -471,7 +471,7 @@ Jedna strona (Jinja2 template + vanilla JS + CSS, serwowane z tego samego FastAP
|
||||||
- Pole zapytania + submit (Enter albo przycisk).
|
- Pole zapytania + submit (Enter albo przycisk).
|
||||||
- Wyniki grupowane po `envelope_id` (dokument), w obrębie dokumentu chunki
|
- Wyniki grupowane po `envelope_id` (dokument), w obrębie dokumentu chunki
|
||||||
posortowane po `dist`.
|
posortowane po `dist`.
|
||||||
- Kolorowanie progów (progi z fazy 3, `docs/kb/modules/05-faza3-plan.md` §1.2,
|
- Kolorowanie progów (progi z fazy 3, `kb/phases/kb-m5-faza3.md` §1.2,
|
||||||
zweryfikowane bramką): `dist < 0.45` zielony, `0.45–0.55` żółty, `> 0.55` —
|
zweryfikowane bramką): `dist < 0.45` zielony, `0.45–0.55` żółty, `> 0.55` —
|
||||||
**nie renderować wyniku**, tylko komunikat "brak odpowiedzi w KB" (żółta/czerwona
|
**nie renderować wyniku**, tylko komunikat "brak odpowiedzi w KB" (żółta/czerwona
|
||||||
strefa nadal renderuje wynik z ostrzeżeniem wizualnym; czerwona = brak sensownego
|
strefa nadal renderuje wynik z ostrzeżeniem wizualnym; czerwona = brak sensownego
|
||||||
|
|
|
||||||
53
kb/phases/monitoring-floty-prometheus.md
Normal file
53
kb/phases/monitoring-floty-prometheus.md
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: phase
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-08-03
|
||||||
|
links:
|
||||||
|
- backlog.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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. ✅ ZROBIONE (2026-06-26, commit `7d4014e`) — Inwentaryzacja nodów floty `100.x` do
|
||||||
|
scrape. Dodane: piha/solaria/lustro (`node:` label), vps zachowany. Saturn pominięty
|
||||||
|
(workstation), chelsty/chelsty-infra pominięte (node_exporter down z VPS → osobny wpis).
|
||||||
|
3. Container-layer exporter (cAdvisor lub lekki docker-state) — `node_exporter` nie widzi
|
||||||
|
kontenerów.
|
||||||
|
4. ✅ ZROBIONE (2026-06-30, commit `d417000`) — Reguły liveness (`up==0 for: 5m`).
|
||||||
|
`rules/liveness.yml`: `NodeDown expr up{node=~"vps|piha"}==0 for 5m severity critical`.
|
||||||
|
Only always-on (vps, piha); solaria/lustro świadomie wykluczone (intermittent → anomaly
|
||||||
|
detection). Deploy: fleet-prometheus Recreated (zmiana compose), reguła inactive=poprawnie.
|
||||||
|
5. ✅ ZROBIONE (2026-06-30, commit `62d6fc0`) — brain-watchdog: drugie wejście — poll
|
||||||
|
Prometheus `/api/v1/alerts` (`firing`) → Telegram. Architektura A: dwa niezależne tory,
|
||||||
|
mózg NIETKNIĘTY, debounce per-alert (klucz alertname:node w state.json). 12 testów pass.
|
||||||
|
PENDING zamknięty 2026-07-02: poll POTWIERDZONY reconem (obraz zbudowany po `62d6fc0`,
|
||||||
|
`PROMETHEUS_URL` w `.env` i w env kontenera, zero poll failed) — patrz
|
||||||
|
`kb/subsystems/fleet-inventory-verify.md`.
|
||||||
|
✅ END-TO-END UDOWODNIONE 2026-07-06 (Etap 0 cutoveru): tor Prometheus →
|
||||||
|
watchdog → Telegram potwierdzony w produkcji testem `AlertTestEtap0`
|
||||||
|
(firing → log polla → Telegram → rollback) — patrz `docs/sessions/2026-07-06.md`.
|
||||||
|
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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -164,7 +164,7 @@ Skutek uboczny do zaakceptowania świadomie: syntetyczne `node_stale`/
|
||||||
wyłączeniu **wcześniej, ale nie liczniej** — te eventy już dziś powstają co noc
|
wyłączeniu **wcześniej, ale nie liczniej** — te eventy już dziś powstają co noc
|
||||||
(21:32/21:39 dla lustro, każdorazowo dla solaria). Cutover nie zwiększa wolumenu
|
(21:32/21:39 dla lustro, każdorazowo dla solaria). Cutover nie zwiększa wolumenu
|
||||||
alertów. Docelowe wyciszenie planowych okien off to wątek anomaly-detection
|
alertów. Docelowe wyciszenie planowych okien off to wątek anomaly-detection
|
||||||
z backlogu (`docs/backlog.md:390-406`) — **niezależny od cutoveru i nieblokujący**;
|
z backlogu (`kb/phases/backlog.md:390-406`) — **niezależny od cutoveru i nieblokujący**;
|
||||||
`NodeDown` dla solaria/lustro słusznie pozostaje wyłączony.
|
`NodeDown` dla solaria/lustro słusznie pozostaje wyłączony.
|
||||||
|
|
||||||
### Rekomendowany mapping (potwierdzenie rekomendacji z recon F/Etap 2)
|
### Rekomendowany mapping (potwierdzenie rekomendacji z recon F/Etap 2)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ links: []
|
||||||
|
|
||||||
# Plan naprawy subsystemu A (control-plane) — 2026-07-28
|
# Plan naprawy subsystemu A (control-plane) — 2026-07-28
|
||||||
|
|
||||||
Kontekst: docs/architecture/RECON-multiagent-2026-07-27.md. Decyzje bazowe:
|
Kontekst: kb/subsystems/recon-multiagent.md. Decyzje bazowe:
|
||||||
- Flota dzieli się na dwa subsystemy. A = utrzymaniowy (control-plane, node-agenty,
|
- Flota dzieli się na dwa subsystemy. A = utrzymaniowy (control-plane, node-agenty,
|
||||||
self-healing) — ten plan. B = zleceniowy (dyspozytor + Telegram + KB + HA +
|
self-healing) — ten plan. B = zleceniowy (dyspozytor + Telegram + KB + HA +
|
||||||
homelab-ops) — prowadzony w osobnym projekcie, poza tym planem.
|
homelab-ops) — prowadzony w osobnym projekcie, poza tym planem.
|
||||||
|
|
|
||||||
60
kb/runbooks/control-plane-deploy-recovery.md
Normal file
60
kb/runbooks/control-plane-deploy-recovery.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: runbook
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-05-27
|
||||||
|
links:
|
||||||
|
- ../subsystems/control-plane.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Control-plane — deployment i recovery
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### From SATURN (primary control node)
|
||||||
|
```bash
|
||||||
|
# Full deploy via SSH
|
||||||
|
./scripts/deploy/deploy-control-plane.sh --ssh
|
||||||
|
|
||||||
|
# Or manually:
|
||||||
|
ssh oskar@100.95.58.48 "cd ~/homelab-codex-ws && git pull origin master && cd services/control-plane && docker compose up -d --build --force-recreate"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Direct on VPS
|
||||||
|
```bash
|
||||||
|
cd ~/homelab-codex-ws/services/control-plane
|
||||||
|
docker compose up -d --build --force-recreate
|
||||||
|
```
|
||||||
|
|
||||||
|
`deploy-local.sh` also creates the required `/opt/homelab/` directory structure and sets ownership to UID 1000 (requires `sudo`). If directories already exist, skip to the `docker compose` step directly.
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
```bash
|
||||||
|
# On VPS
|
||||||
|
docker ps --filter "name=control-plane"
|
||||||
|
curl -s http://localhost:18180/summary | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recovery
|
||||||
|
|
||||||
|
### World state is stale or corrupt
|
||||||
|
```bash
|
||||||
|
# On VPS — delete checkpoint to force full replay
|
||||||
|
rm /opt/homelab/state/observer_checkpoint.json
|
||||||
|
docker restart control-plane-observer
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flood of pending actions after bootstrap
|
||||||
|
Check if node-agent is running and emitting `service_healthy` events on each node. Without `service_healthy`, the supervisor sees all services as missing and queues redeployments every cycle.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check node-agent on each node
|
||||||
|
ssh oskar@<node> "docker ps --filter name=node-agent && docker logs node-agent --tail 20"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rebuild from scratch
|
||||||
|
```bash
|
||||||
|
ssh oskar@100.95.58.48 "cd ~/homelab-codex-ws/services/control-plane && docker compose up -d --build --force-recreate"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ links:
|
||||||
|
|
||||||
## First-time deployment
|
## First-time deployment
|
||||||
|
|
||||||
See **[DEPLOY.md](DEPLOY.md)** for the full procedure: HA token creation,
|
See **[DEPLOY.md](ha-diag-agent-deploy.md)** for the full procedure: HA token creation,
|
||||||
per-host `.env` config, deploy commands, verification steps, 48h shadow-mode
|
per-host `.env` config, deploy commands, verification steps, 48h shadow-mode
|
||||||
observation, and rollback.
|
observation, and rollback.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ links:
|
||||||
## Deploy (PIHA)
|
## Deploy (PIHA)
|
||||||
|
|
||||||
0. Prerequisite: `ollama-piha` deployed and `bge-m3` pulled — see
|
0. Prerequisite: `ollama-piha` deployed and `bge-m3` pulled — see
|
||||||
`services/ollama-piha/README.md` (the pull is a **manual** deploy step).
|
`kb/services/ollama-piha.md` (the pull is a **manual** deploy step).
|
||||||
1. `git pull` on PIHA (`~/homelab-codex-ws`).
|
1. `git pull` on PIHA (`~/homelab-codex-ws`).
|
||||||
2. `cp services/kb-query/env.example services/kb-query/.env` and fill in the
|
2. `cp services/kb-query/env.example services/kb-query/.env` and fill in the
|
||||||
real `KB_DSN` password (the template already sets `EMBED_FALLBACK_URL`).
|
real `KB_DSN` password (the template already sets `EMBED_FALLBACK_URL`).
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ bind-mount the existing model directory.**
|
||||||
docker exec ollama ollama ps
|
docker exec ollama ollama ps
|
||||||
```
|
```
|
||||||
3. Embeddings endpoint + vector dimension (deferred check from
|
3. Embeddings endpoint + vector dimension (deferred check from
|
||||||
`docs/kb/modules/05-faza2-plan.md` §6 step 2):
|
`kb/phases/kb-m5-faza2.md` §6 step 2):
|
||||||
```bash
|
```bash
|
||||||
curl -s http://localhost:11434/api/embeddings -d '{"model":"bge-m3","prompt":"test"}' \
|
curl -s http://localhost:11434/api/embeddings -d '{"model":"bge-m3","prompt":"test"}' \
|
||||||
| python3 -c "import json,sys; v=json.load(sys.stdin)['embedding']; print(len(v))"
|
| python3 -c "import json,sys; v=json.load(sys.stdin)['embedding']; print(len(v))"
|
||||||
|
|
@ -145,7 +145,7 @@ SOLARIA:
|
||||||
- Given the missing driver, the cutover proceeded **in CPU-only mode**: the
|
- Given the missing driver, the cutover proceeded **in CPU-only mode**: the
|
||||||
`deploy.resources` GPU reservation was commented out in
|
`deploy.resources` GPU reservation was commented out in
|
||||||
`services/ollama/docker-compose.yml` (commit `f57a01a`), and the driver fix
|
`services/ollama/docker-compose.yml` (commit `f57a01a`), and the driver fix
|
||||||
was filed as a backlog item (see `docs/backlog.md`) blocking the module 5
|
was filed as a backlog item (see `kb/phases/backlog.md`) blocking the module 5
|
||||||
mail-embedding phase.
|
mail-embedding phase.
|
||||||
- **2026-07-16: driver fixed.** Installed `nvidia-driver-595-open` from the
|
- **2026-07-16: driver fixed.** Installed `nvidia-driver-595-open` from the
|
||||||
distro repository — not the old `ppa:graphics-drivers/ppa` (jammy), which
|
distro repository — not the old `ppa:graphics-drivers/ppa` (jammy), which
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ links:
|
||||||
wildcard `*.kapala.org` już pokrywa tę subdomenę, nowy cert niepotrzebny.
|
wildcard `*.kapala.org` już pokrywa tę subdomenę, nowy cert niepotrzebny.
|
||||||
Plus vhost w npm@PIHA (HTTPS → `192.168.31.5:8210`, Advanced puste).
|
Plus vhost w npm@PIHA (HTTPS → `192.168.31.5:8210`, Advanced puste).
|
||||||
6. `docker compose up -d` + `./healthcheck.sh` + testowy login OIDC.
|
6. `docker compose up -d` + `./healthcheck.sh` + testowy login OIDC.
|
||||||
7. Export NFS dla workera (patrz `services/paperless-worker/README.md`) —
|
7. Export NFS dla workera (patrz `kb/services/paperless-worker.md`) —
|
||||||
dopiero przy module 3.
|
dopiero przy module 3.
|
||||||
8. Wpis w `hosts/piha/services.yaml` (dopiero przy deployu — wcześniej
|
8. Wpis w `hosts/piha/services.yaml` (dopiero przy deployu — wcześniej
|
||||||
supervisor widziałby drift dla nieistniejącego serwisu).
|
supervisor widziałby drift dla nieistniejącego serwisu).
|
||||||
|
|
|
||||||
|
|
@ -64,4 +64,4 @@ Weryfikacja po deployu: `./healthcheck.sh` robi test zapisu na mount.
|
||||||
`inventory/topology.yaml` (obecnie SOLARIA ma tam tylko `node-agent`) —
|
`inventory/topology.yaml` (obecnie SOLARIA ma tam tylko `node-agent`) —
|
||||||
bez tego supervisor/observer nie widzą tego serwisu w desired-state, więc
|
bez tego supervisor/observer nie widzą tego serwisu w desired-state, więc
|
||||||
drift między `hosts/solaria/services.yaml` a rzeczywistością nie jest
|
drift między `hosts/solaria/services.yaml` a rzeczywistością nie jest
|
||||||
wykrywany. Patrz `docs/backlog.md`.
|
wykrywany. Patrz `kb/phases/backlog.md`.
|
||||||
|
|
|
||||||
31
kb/runbooks/service-operational-recovery.md
Normal file
31
kb/runbooks/service-operational-recovery.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: runbook
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-05-11
|
||||||
|
links:
|
||||||
|
- ../subsystems/service-lifecycle.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# Serwisy — operational recovery
|
||||||
|
|
||||||
|
## Operational Recovery
|
||||||
|
|
||||||
|
### 1. Container Failure
|
||||||
|
If a service is unhealthy:
|
||||||
|
- Check `docker compose logs`.
|
||||||
|
- Restart: `docker compose restart`.
|
||||||
|
- Recreate: `docker compose up -d --force-recreate`.
|
||||||
|
|
||||||
|
### 2. Node Failure
|
||||||
|
If a host node fails:
|
||||||
|
- Services with `owner_node` matching the failed node must be recovered on a backup node or the node must be restored.
|
||||||
|
- Persistence data must be restored from backups to `/opt/homelab/data/<service>`.
|
||||||
|
|
||||||
|
### 3. Dependency Recovery
|
||||||
|
If a dependency fails:
|
||||||
|
- Services depending on it might report unhealthy status.
|
||||||
|
- Recover the dependency first.
|
||||||
|
- Re-verify dependent services.
|
||||||
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
|
---
|
||||||
|
okf: "0.1"
|
||||||
|
type: runbook
|
||||||
|
visibility: private
|
||||||
|
status: active
|
||||||
|
updated: 2026-05-17
|
||||||
|
links:
|
||||||
|
- ../subsystems/stability-agent-architektura.md
|
||||||
|
---
|
||||||
|
|
||||||
# Stability Agent Multi-Node Rollout
|
# Stability Agent Multi-Node Rollout
|
||||||
|
|
||||||
## Architecture Summary
|
|
||||||
The `stability-agent` is a lightweight Python service that monitors node health (disk, Docker containers, Tailscale, MQTT) and publishes state to a central Redis instance running on **PIHA**.
|
|
||||||
|
|
||||||
- **Source**: `services/stability-agent`
|
|
||||||
- **State Path**: `/opt/homelab/state`
|
|
||||||
- **Events Path**: `/opt/homelab/events`
|
|
||||||
- **Redis Target**: `100.108.208.3:6379` (PIHA)
|
|
||||||
|
|
||||||
## Why UI only showed CHELSTY
|
|
||||||
Previously, the `stability-agent` had `NODE_NAME` defaulted to `chelsty` and was only deployed there. The Agent System UI materializer on PIHA filters nodes based on the Redis keys `homelab:nodes:<NODE_NAME>`. Without other agents publishing their specific `NODE_NAME`, the UI remained limited to the single active node.
|
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Use the helper script to deploy or generate commands. The script uses explicit Tailscale IPs for remote targets (piha, chelsty, vps) and runs locally for solaria.
|
Use the helper script to deploy or generate commands. The script uses explicit Tailscale IPs for remote targets (piha, chelsty, vps) and runs locally for solaria.
|
||||||
|
|
@ -5,7 +5,8 @@ visibility: private
|
||||||
status: active
|
status: active
|
||||||
updated: 2026-08-03
|
updated: 2026-08-03
|
||||||
stub: true
|
stub: true
|
||||||
links: []
|
links:
|
||||||
|
- ../subsystems/control-plane.md
|
||||||
---
|
---
|
||||||
|
|
||||||
# control-plane
|
# control-plane
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ links:
|
||||||
|
|
||||||
# ha-mcp — read-only MCP server for Home Assistant
|
# ha-mcp — read-only MCP server for Home Assistant
|
||||||
|
|
||||||
**Status: phase 2a** of `services/home-assistant/DESIGN.md` — own minimal MCP
|
**Status: phase 2a** of `kb/decisions/ha-configs-as-code.md` — own minimal MCP
|
||||||
server (the alternative, adopting `hass-mcp`, was the other option in that
|
server (the alternative, adopting `hass-mcp`, was the other option in that
|
||||||
document's Open questions; operator decision 2026-07-30: build our own).
|
document's Open questions; operator decision 2026-07-30: build our own).
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ in this server that changes anything in Home Assistant:
|
||||||
**The write path back into Home Assistant is unchanged and lives elsewhere:**
|
**The write path back into Home Assistant is unchanged and lives elsewhere:**
|
||||||
edit `services/home-assistant/config/<instance>/` in the repo, then
|
edit `services/home-assistant/config/<instance>/` in the repo, then
|
||||||
`scripts/ha/deploy.sh <instance>` (drift-abort → `check_config` → write →
|
`scripts/ha/deploy.sh <instance>` (drift-abort → `check_config` → write →
|
||||||
verify). See `services/home-assistant/DESIGN.md`, "Sync model" and
|
verify). See `kb/decisions/ha-configs-as-code.md`, "Sync model" and
|
||||||
"Validation gate". Nothing in this server bypasses that, and nothing in this
|
"Validation gate". Nothing in this server bypasses that, and nothing in this
|
||||||
server should ever learn to.
|
server should ever learn to.
|
||||||
|
|
||||||
|
|
@ -140,7 +140,7 @@ down — you then get `live_error` instead of `live`.
|
||||||
|
|
||||||
## Why `unavailable` is in every result
|
## Why `unavailable` is in every result
|
||||||
|
|
||||||
The 2026-07-23 audit (`services/home-assistant/docs/audyt-automatyzacji-2026-07-23.md`,
|
The 2026-07-23 audit (`kb/audits/ha-automatyzacje-2026-07-23.md`,
|
||||||
1.2–1.4) traced ~15 silently broken automations to dead sensors: a condition
|
1.2–1.4) traced ~15 silently broken automations to dead sensors: a condition
|
||||||
on an `unavailable` entity is simply never true, and HA reports no error. So
|
on an `unavailable` entity is simply never true, and HA reports no error. So
|
||||||
every entity view here carries an explicit `unavailable: true` plus
|
every entity view here carries an explicit `unavailable: true` plus
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue