SIGN IN SIGN UP

feat: Rust CLI — declarative alert rules, deterministic engine, replay source (LEO-335) (#24)

* feat: Rust CLI — declarative alert rules, deterministic engine, replay source (LEO-335)

A strict [[rules]] config section (threshold/rate/stale/missing/
source-unavailable, with hysteresis, debounce, and per-series state), a
deterministic sample-count-based engine emitting fired/cleared
transitions, and the SampleSource abstraction: LiveSource (fresh HWiNFO
session per poll) and ReplaySource (logged JSONL, bounded reads,
Python-era NaN-token fixup). No new CLI subcommand — the engine ships
test-first and gets wired to the watch command in LEO-336.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: bind a named LiveSource before calling next_tick (review readability)

Addresses the round-1 Copilot comment. Note the original code did
compile and pass (method-call auto-ref mutably borrows the temporary;
the cfg(not(windows)) test ran green on ubuntu CI) — the change is for
readability: a named mutable binding mirrors how a real caller holds a
source across ticks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* review round 2: address non-blocking findings from agent reviewers

- engine: the rate NaN comment now says what the code does — only the
  delta's ENDPOINTS can make it unevaluable; a NaN strictly inside the
  window is invisible. Kept endpoint semantics deliberately (poisoning
  would blind the rule for a whole window after every blip) and pinned
  it with the reviewer's 10 -> NaN -> 30 scenario as a permanent test.
- engine: Transition equality is now NaN-reflexive (hand-written
  PartialEq mirroring the safe wrapper's Reading), so identical replays
  carrying NaN payloads compare equal; the determinism test now runs a
  dead NaN rail through the comparison to prove it.
- rules: kind-independent validation (matcher patterns, finiteness,
  clear side, for_samples range) moved before the kind gate, so a rule
  missing its kind still gets its other problems aggregated; pinned.
- SECURITY.md: enumerate replayed JSONL as parsed untrusted input in
  the Current-implementation attack-surface list — this PR ships the
  first read-back parser, and the round-1 PR-body claim that it was
  already enumerated was wrong (credit: lcj-claude-reviewer).

Not changed, deliberately: LiveSource's debug-level source-loss logging
(the warn-once latch is a command-loop concern, LEO-336) and the O(n^2)
duplicate-name scan (rule counts are hand-written-config tiny).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Agent for Leonard Janke <leonard.janke.agent@proton.me>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
L
lcj-claude-coder committed
3ecc0fc8db0a0690da7916388fa2f10d684560fb
Parent: de15106
Committed by GitHub <noreply@github.com> on 7/3/2026, 2:46:03 AM