8983231196
GREEN phase (TDD) for Task 1: extractCandidateLinks (cheerio a[href] + footer-noise filter + MAX_LINKS_PER_EMAIL cap, plaintext regex fallback), titleFromEmail (subject -> first body line -> fallback), and sourceNoticeIdFor (sha256 link hash) implement D-04's generic, no-portal- specific-parser evaluation of alert emails. SourceType gains 'email-alert'; TenderNormalizerService routes it through the existing normalizeBag() path (same as ai-netserver/cosinex-dtvp/rss). EmailAlertAdapter.fetchTenders() is a Task-1 placeholder — Task 2 wires the real per-tenant fan-out. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>