Files
opcda-diagnozer/TODO.md
T
2026-10-08 07:57:21 +02:00

5.6 KiB
Raw Blame History

TODO — implementation status

Companion to docs/IMPLEMENTATION_PLAN.md (the authoritative plan) and CHANGELOG.md (what shipped). One row per plan task; updated as work lands. Legend: [done] complete & verified · [partial] some of it landed · [todo] not started · [skip] dropped by decision.

Phase 0 — Feasibility & environment [done]

  • [done] Wrapper backend decision: OPC DA Automation Wrapper (OPC.Automation) → 32-bit interpreter mandatory (spec §11).
  • [done] Test server: Matrikon OPC Simulation Server, local ProgID Matrikon.OPC.Simulation.1; baseline read RTT + wrapper error shapes recorded (repo memory).
  • [done] Dependencies chosen for a 32-bit, no-compiler install: ruamel.yaml (PyYAML has no cp314 win32 wheels), pywin32.

Phase 1 — Core engine [done]

  • [done] 1. config.py — typed YAML config + strict validation; D16 devices: indicators with configurable ok_values; check-config prints them.
  • [done] 2. quality.py — decode tables (spec §7) + status_text(raw) -> "NAME / SUBCODE (0xNN)" clear-text helper.
  • [done] 3. opc/base.py — client/browser protocols, ReadResult, OpcError with decoded HRESULT.
  • [done] 4. opc/automation.py — connect / browse / read (per-item Item.Read; SyncRead is unmarshallable from pywin32 — verified), per-tag errors, safe COM teardown.
    • [skip] Single persistent group + static items (poller creates its own per client; the throwaway-group read pattern is verified).
  • [done] 5. monitor/state.py — connection state machine, exponential backoff (1 s → 60 s cap, reset on success), reconnect accounting, D3 flapping window (pure, clock-fed).
  • [done] 6. monitor/detectors.py — D4–D16 pure detectors + rolling window: latency spike/streak/p95 (D4–D6), quality transitions/persistence/flapping (D8–D11), stale/frozen (D12–D13), mass-bad latch (D14), D16 device-link (ok_values edge-level DOWN/UP).
  • [done] 7. monitor/poller.py — coordinator + dedicated COM worker thread (client born on the worker), D7 soft-hang flag, hard-hang watchdog (abandon + rebuild), backoff between sessions.
    • [open] Poll source default (CACHE vs DEVICE) — needs a spec decision: Matrikon shows BAD qualities on some tags only via CACHE.
  • [done] 8. run verb — foreground monitoring loop, console reporter with clear-text status, heartbeat (D15), Ctrl+C stop (second Ctrl+C aborts).
  • [done] 9. opc/fake.py — scenario engine: scripted polls (exact results / "good" shorthand) and PollScriptError whole-call failures; hang clients are plain sleeping fakes in tests.
    • [open] D12 stale events re-emit every poll while a tag stays stale — the spec defines the condition per-poll; ops may want debounce/latch (decide before the 24 h soak; live sim output showed the spam clearly).

Phase 2 — Reporters [done]

  • [done] 1. report/jsonl.py — rotating JSONL (size + backups), config-digest header line, single-line atomic-ish appends. Live-verified.
  • [done] 2. report/textlog.py — plain-text anomaly log (spec §9.1): anomalies-YYYYMMDD.log, one line per detected anomaly, clear-text status NAME / SUB (0xNN), recoveries logged (incident narrative), per-day files, shared rotation. Live-verified.
  • [done] 3. report/eventlog.py — Windows Event Log (WARN+), severity-mapped via a RegisterEventSource handle + positional ReportEvent (keyword args raise TypeError — found live). Source message-file registration lands with install (Phase 3). Live-verified delivery.
  • [done] 4. report/http.py — optional webhook (report.http config), bounded queue + daemon sender, never blocks the poll loop; failures counted and dropped, injectable post for tests.
  • [done] 5. Heartbeat assembly (D15, Phase 1) + reporter fan-out dispatcher (report/base.py): per-sink failure isolation, best-effort close. The run verb wires console + JSONL + textlog + eventlog (+http when set).

Phase 3 — Windows service

  • [todo] 1. service.py — ServiceFramework host; clean stop (STOP_PENDING, join-with-timeout, abandon hung COM thread).
  • [todo] 2. CLI verbs install/uninstall/start/stop (sc.exe semantics).
  • [todo] 3. SCM recovery (sc failure ... restart), auto-start, service account docs.
  • [todo] 4. %ProgramData%\OPCDA-Diagnozer\ config/log dir conventions (frozen exe already defaults there).
  • [open] Frozen-exe SCM hosting: console exe must expose ServiceMain — one careful build pass (pywin32 ServiceControlDispatcher).

Phase 4 — Integration & chaos testing

  • [todo] Scenario matrix vs the sim server: server kill / service stop / firewall silent drop / latency injection / device comm failure / quality oscillation / stale+frozen / mass bad / config errors / D16: flip a device indicator (e.g. a P500x.Connected alias).
  • [todo] 24 h soak (AC10): no leaks, reconnect accounting correct, heartbeats every 5 min, ≤ ~50 MB RAM, ~0 % CPU idle.

Phase 5 — Packaging & docs

  • [done] PyInstaller exe build (scripts/build_exe.ps1, onedir + onefile, read canary) — live-verified.
  • [done] README (install, config, DCOM checklist, HRESULT table).
  • [todo] Ops runbook: reading events, kind meanings (spec §12 matrix), threshold tuning, evidence locations.
  • [todo] 1.0.0 tag once AC1–AC10 pass.

Housekeeping

  • [todo] Wire status_text into read/probe output once it exists (currently shows raw_hex + decoded name separately).
  • [todo] Record the CACHE-vs-DEVICE poll-source decision in the spec once made; add fake-client scripted reads for both sources to the poller tests.