homelab-codex-ws/services
oskar 71a7af5b3f fix(control-plane): unwedge incidents that never get service_healthy
_resolve_incident() only ever fires from process_event() on a
service_healthy/service_recovered event. A service that is removed,
renamed, or was only ever a one-off test never emits that event again,
so its incident stays "active" in world/incidents.json forever — this
is what left 5 incidents wedged on VPS until a manual on-node edit
during the 2026-08-26 recon session (docs/sessions/2026-08-26.md).

Two independent unwedging mechanisms, both in observer._prune_stale_world
(runs every cycle, so no new event is required to trigger either):

(a) Time-based fallback: any active incident with last_occurrence older
    than INCIDENT_STALE_RESOLVE_SECS (env, default 24h) auto-resolves
    with resolved_reason="auto_stale_no_events_24h". Unlike the existing
    orphan case (Case 2, 5-min guard, only unlinked incidents), this
    also clears a service's lingering incident_id link — that link is
    exactly what a decommissioned service's incident never gets a
    chance to clear via the normal event path.

(b) Manual path: an operator touches
    world/resolve-requests/<incident-id>; the observer consumes the
    flag file each cycle, force-resolves with resolved_reason=
    "manual_operator", and always removes the flag (even for an
    unknown/already-resolved id) so a mistyped flag can't sit forever
    looking unprocessed.

    Chose a flag file over adding a mutation endpoint to operator_ui.py:
    /action/mutate only knows actions/<status>/<id>.json, there is no
    incidents equivalent, and world/incidents.json is exclusively
    observer-owned (rewritten wholesale every cycle by _save_world) —
    a second writer (the HTTP handler thread) would race the observer's
    own writes. A flag file needs no new HTTP surface and reuses the
    same "operator drops a file, the owning process consumes it"
    pattern the actions pending/approved queue already uses. Smaller
    diff, no new attack surface on a server with no auth on writes.

Tests added to test_incident_lifecycle.py: stale-resolve past the
threshold (service still linked), negative case (fresh active incident
stays active), configurable threshold, manual-flag resolve + flag
removal, flag for an unknown incident, flag for an already-resolved
incident. Full control-plane suite: 179 passed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017WDKj5LRY8vdQMx57dfNnu
2026-08-26 21:05:38 +02:00
..
agent-system fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
brain-watchdog fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
control-plane fix(control-plane): unwedge incidents that never get service_healthy 2026-08-26 21:05:38 +02:00
fleet-prometheus feat(mail-sync): scheduler PIHA, takt kb-ingest, runbook i dokumentacja 2026-08-06 15:30:57 +02:00
forgejo fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
gokapi fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
ha-diag-agent fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
ha-mcp fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
home-assistant fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
kb-postgres feat(kb-mail): adapter IMAP + model stanu synca + migracja 005 2026-08-06 15:30:57 +02:00
kb-query feat(kb-query): domyslny mode /search = hybrid (DoD (d) fazy mailowej) 2026-08-06 13:30:06 +02:00
kb-site docs(kb-site): przekaz ACCESS_TOKEN generatorowi w procedurze publikacji 2026-08-05 22:26:48 +02:00
llm-gateway fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
mosquitto fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
narty27 fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
nextcloud fix(kb): 13 pozostalych odwolan do sciezek sprzed migracji 2026-08-04 17:02:12 +02:00
node-agent fix(dispatch): inbox 0o775 + rsync rc=23 przestaje byc cichy 2026-08-06 13:42:47 +02:00
node_exporter fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
npm fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
ollama fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
ollama-piha fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
paperless fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
paperless-worker fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
planner-agent fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
stability-agent fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
vikunja fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
zigbee2mqtt fix(kb): README-wskazniki dla services i hosts + wyjatek ken-legacy 2026-08-04 16:58:46 +02:00
.gitkeep Add infrastructure standards and deployment conventions 2026-05-07 21:16:03 +02:00