Rozstrzygniecie 1. Monolit mieszal cztery typy OKF. Rozbity PER TYP po
granicy sekcji `##`:
10 x decision — pozycje backlogu (w tym backlog-aktywne 28 KB
i backlog-zamkniete 12 KB, ktore zostaja calosciami)
7 x incident — bugi/awarie dotad wtopione w backlog: cutover HA ken,
checkpoint observera, ha-diag-agent node=unknown,
deploy-local ghost-kontenery, paperless-worker config,
deploy-node nie przebudowuje obrazu, ollama bez sterownika
2 x phase — HA configs-as-code, monitoring floty Prometheus
kb/phases/backlog.md zostaje jako cienki indeks (type: phase, status: active):
oryginalna preambula + wygenerowany spis linkow do wszystkich 19 elementow.
23 przychodzace odwolania zostaja przepiete na ta sciezke w grupie 7.
NIE rozbijano po `###` (38 pozycji w "Aktywne" + 13 w "Zamkniete" = 51
plikow). Rozstrzygniecie mowi "rozbij per typ", a nie per pozycja;
rozdrobnienie do 51 plikow rozerwaloby czytelnosc backlogu.
Kontrola: preambula + 19 sekcji == oryginal z HEAD (multizbior niepustych
linii). Tresc pozycji nietknieta.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2.9 KiB
| okf | type | visibility | status | updated | links | |
|---|---|---|---|---|---|---|
| 0.1 | incident | private | active | 2026-08-03 |
|
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.