homelab-codex-ws/services/ha-diag-agent/src/ha_diag
oskar f2ba81bcc1 fix(ha-diag): node_name from env + fail-fast on unknown — evt-unknown-* files poisoned observer checkpoint (see d5139c9)
An "unknown"/empty node_name silently produced evt-unknown-* event files. One
landed in events/piha/ and, being lexically greater than every evt-piha-* name,
pinned the observer's (then lexical) checkpoint and blocked PIHA for ~34 days.

Defense in depth, two layers, both refuse rather than emit poison:
- config.py: node_name field_validator rejects ""/"unknown" (case-insensitive,
  trimmed); validate_default=True so the "unknown" default itself is rejected
  when NODE_NAME never reaches the process. main() catches ValidationError and
  exits 1 with a clear FATAL message instead of a raw traceback.
- event_emitter.py: EventEmitter.__init__ guards node_name at the exact poison
  site (node_name is embedded in the filename), so no future call path can
  reintroduce evt-unknown-*.

Precedence unchanged and correct: Settings.load() uses os.environ.setdefault, so
env NODE_NAME wins over YAML; YAML only supplies node_name when env is absent.
api.py never writes event files (only /health, /trigger), so its _node_name
global cannot produce poison — verified, left as-is.

Tests (services/ha-diag-agent/tests/): new test_config.py (env load, env>YAML
precedence, fail-fast on unknown/empty/whitespace/default/YAML-unknown) and
EventEmitter guard tests. Full unit suite: 139 passed, 0 regressions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 19:48:58 +02:00
..
checks feat(ha-diag-agent): three REST diagnostic checks + Phase 3 flag fixes 2026-05-29 14:43:10 +02:00
monitors feat(ha-diag-agent): WebSocketMonitor for real-time HA liveness 2026-05-29 15:00:18 +02:00
__init__.py feat(ha-diag-agent): scaffold service with HA REST client and event emitter 2026-05-29 12:26:34 +02:00
api.py feat(ha-diag-agent): WebSocketMonitor for real-time HA liveness 2026-05-29 15:00:18 +02:00
config.py fix(ha-diag): node_name from env + fail-fast on unknown — evt-unknown-* files poisoned observer checkpoint (see d5139c9) 2026-07-15 19:48:58 +02:00
event_emitter.py fix(ha-diag): node_name from env + fail-fast on unknown — evt-unknown-* files poisoned observer checkpoint (see d5139c9) 2026-07-15 19:48:58 +02:00
ha_client.py feat(ha-diag-agent): three REST diagnostic checks + Phase 3 flag fixes 2026-05-29 14:43:10 +02:00
main.py fix(ha-diag): node_name from env + fail-fast on unknown — evt-unknown-* files poisoned observer checkpoint (see d5139c9) 2026-07-15 19:48:58 +02:00
models.py feat(ha-diag-agent): WebSocketMonitor for real-time HA liveness 2026-05-29 15:00:18 +02:00
storage.py feat(ha-diag-agent): three REST diagnostic checks + Phase 3 flag fixes 2026-05-29 14:43:10 +02:00