🚧 WIP
This commit is contained in:
@@ -15,42 +15,46 @@ Legend: **[done]** complete & verified · **[partial]** some of it landed ·
|
||||
- [done] Dependencies chosen for a 32-bit, no-compiler install:
|
||||
ruamel.yaml (PyYAML has no cp314 win32 wheels), pywin32.
|
||||
|
||||
## Phase 1 — Core engine
|
||||
## 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).
|
||||
- [todo] `status_text(raw) -> "NAME (0xNN)"` clear-text helper (spec §7
|
||||
closing rule; used by every reporter).
|
||||
- [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 will create its own
|
||||
- [skip] Single persistent group + static items (poller creates its own
|
||||
per client; the throwaway-group read pattern is verified).
|
||||
- [todo] 5. `monitor/state.py` — connection state machine, exponential
|
||||
backoff (1 s → 60 s cap), reconnect accounting (only the enum exists).
|
||||
- [todo] 6. `monitor/detectors.py` — D1–D15 pure detectors + rolling window
|
||||
(only the `PollOutcome` dataclass exists).
|
||||
- [todo] **D16 device-link detector** (`ok_values` semantics, edge-level,
|
||||
`DEVICE_LINK_DOWN`/`DEVICE_LINK_UP`).
|
||||
- [todo] 7. `monitor/poller.py` — the COM thread poll loop + hang watchdog
|
||||
(abandon & rebuild past `hard_hang_s`).
|
||||
- [todo] Startup tag validation: probe every configured tag (incl. device
|
||||
indicators) before entering the loop; fail fast on invalid ItemIDs.
|
||||
- [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.
|
||||
- [todo] 8. `run` verb — foreground monitoring loop, event pipeline to
|
||||
reporters, heartbeat (D15).
|
||||
- [done] 9. `opc/fake.py` — scriptable fake client (reads already scriptable
|
||||
via `read_results`; hang/error sequences land with the poller).
|
||||
- [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
|
||||
|
||||
- [todo] 1. `report/jsonl.py` — rotating JSONL (size + backups), config-digest
|
||||
header, atomic-ish append.
|
||||
header, atomic-ish append. **The console reporter already emits the same
|
||||
events in `run` (Phase 1); Phase 2 swaps in the fan-out.**
|
||||
- [todo] 2. `report/textlog.py` — **plain-text anomaly log** (spec §9.1):
|
||||
`anomalies-YYYYMMDD.log`, one line per detected anomaly, clear-text status
|
||||
`NAME (0xNN)`, recoveries logged so it reads as an incident narrative.
|
||||
|
||||
Reference in New Issue
Block a user