From PLAN.md step 4. Spec: docs/spec.md. Phase 1.
⟂ Parallel-safe — touches files no other concurrent step touches.
Files: src/flabel/rules/{__init__,fetch,admit,snapshot}.py, tests/test_admit.py, tests/test_snapshot.py, tests/fixtures/rules/*.rules
Changes: fetch.py is the only network I/O in the package, behind an interface a test can point at local files. admit.py implements the per-source policy: wholesale, or ET metadata filter on confidence High and signature_severity Major|Critical, counting each exclusion reason separately. snapshot.py writes content-addressed immutable snapshots with a manifest, and loads them.
Test that proves it: on committed rule fixtures, fetched == admitted + sum(excluded) exactly; a confidence Low rule and a rule with no confidence key are excluded into different counters; #alert lines never admit; ja3.hash / ja4.hash rules are counted separately. Snapshot id is stable across writes of identical content and changes when content changes; rules.rules is sorted so fetch order cannot affect the id; load_snapshot(None) returns the newest; a missing snapshot raises. Reports the real ET Open admitted counts, closing issue #11.
Depends on: 2. Parallel with: 3, 5, 6.
From
PLAN.mdstep 4. Spec:docs/spec.md. Phase 1.Files:
src/flabel/rules/{__init__,fetch,admit,snapshot}.py,tests/test_admit.py,tests/test_snapshot.py,tests/fixtures/rules/*.rulesChanges:
fetch.pyis the only network I/O in the package, behind an interface a test can point at local files.admit.pyimplements the per-source policy: wholesale, or ET metadata filter onconfidence Highandsignature_severity Major|Critical, counting each exclusion reason separately.snapshot.pywrites content-addressed immutable snapshots with a manifest, and loads them.Test that proves it: on committed rule fixtures,
fetched == admitted + sum(excluded)exactly; aconfidence Lowrule and a rule with noconfidencekey are excluded into different counters;#alertlines never admit;ja3.hash/ja4.hashrules are counted separately. Snapshot id is stable across writes of identical content and changes when content changes;rules.rulesis sorted so fetch order cannot affect the id;load_snapshot(None)returns the newest; a missing snapshot raises. Reports the real ET Open admitted counts, closing issue #11.Depends on: 2. Parallel with: 3, 5, 6.