feat(kagi-news): add semantic deduplication via Claude Haiku master
Adds an LLM-based dedup layer to catch stories that share an event but differ in GUID/headline (same report from different outlets, rewrites, etc.). Exact-GUID filtering still runs first; semantic dedup only considers stories within the same feed posted in a configurable lookback window. Changes: - New SemanticDeduplicator using claude-haiku-4-5 with a tool-use schema for structured duplicate reports; fails open on transient Anthropic API errors so posting is never blocked by network issues - DedupConfig (semantic_enabled, similarity_threshold, lookback_days) with validation, wired through ConfigLoader and config.example.yaml - Aggregator reworked into three phases: GUID filter -> semantic filter -> post, with per-feed counters for new/failed/exact/semantic - StateManager.mark_posted now stores title + summary_snippet, and get_recent_stories returns the lookback window for comparison; state writes are now atomic (tempfile + os.replace) - Requires ANTHROPIC_API_KEY when semantic_enabled is true - Tests: unit tests for SemanticDeduplicator, state manager recent stories + atomic write, and main pipeline integration; live test suite gated behind a `live` pytest marker (excluded by default) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>