ACCEPTANCE CRITERIA (18/18)
☑ 1. `lib/alert-engine.js` exports `loadThresholds(configPath)`, `evaluate(indicator, currentValue, previousValue, threshold)`, `evaluateAll(currentData, previousData, thresholds)`
☑ 2. `loadThresholds` reads and parses `config/thresholds.json`, returns threshold map
☑ 3. `evaluate` returns an `AlertResult` object with fields: indicator, severity, value, previous, delta_pct, threshold_absolute, threshold_delta_pct, triggered_by, timestamp, description
☑ 4. `evaluate` supports two trigger modes: absolute threshold and delta percentage
☑ 5. `evaluate` supports `direction` field ("above" or "below") for absolute comparison
☑ 6. Severity levels: `warning` and `critical` -- critical takes priority when both trigger
☑ 7. `triggered_by` field is "absolute", "delta", or "both"
☑ 8. `evaluate` returns `null` when no threshold is crossed
☑ 9. `evaluateAll` iterates over all indicators and returns array of non-null AlertResults
☑ 10. `lib/rss-parser.js` exports `parseRSS(xmlText)` that returns array of `FeedItem` objects
☑ 11. Each FeedItem has: `title`, `link`, `description`, `pubDate` (ISO 8601), `source` (domain)
☑ 12. Handles RSS 2.0 format (`<item>` tags)
☑ 13. Handles Atom format (`<entry>` tags) as fallback when no RSS items found
☑ 14. Handles CDATA-wrapped content (`<![CDATA[...]]>`)
☑ 15. Strips HTML tags from descriptions
☑ 16. Extracts domain from link URL as `source` field
☑ 17. Filters out items where title or link is empty
☑ 18. Both libs use ONLY Node.js stdlib -- zero npm dependencies