Files
worldmonitor/server
Elie Habib e548e6cca5 feat(intelligence): cross-source signal aggregator with composite escalation (#2143) (#2164)
* feat(intelligence): cross-source signal aggregator with composite escalation (#2143)

Adds a threshold-based signal aggregator seeder that reads 15+ already-seeded
Redis keys every 15 minutes, ranks cross-domain signals by severity, and detects
composite escalation when >=3 signal categories co-fire in the same theater.

* fix(cross-source-signals): wire panel data loading, inline styles, seeder cleanup

- New src/services/cross-source-signals.ts: fetch via IntelligenceServiceClient with circuit breaker
- data-loader.ts: add loadCrossSourceSignals() + startup batch entry (SITE_VARIANT !== 'happy' guard)
- App.ts: add primeVisiblePanelData entry + scheduleRefresh at 15min interval
- base.ts: add crossSourceSignals: 15 * 60 * 1000 to REFRESH_INTERVALS
- CrossSourceSignalsPanel.ts: replace all CSS class usage with inline styles (MarketImplicationsPanel pattern)
- seed-cross-source-signals.mjs: remove dead isMain var, fix afterPublish double-write, deterministic signal IDs, GDELT per-topic tone keys (military/nuclear/maritime) with 3-point declining trend + < -1.5 threshold per spec, bundled topics fallback

* fix(cross-source-signals): complete bootstrap wiring, seeder fixes, cmd-k entry

- cache-keys.ts: add crossSourceSignals to BOOTSTRAP_CACHE_KEYS + BOOTSTRAP_TIERS (slow)
- bootstrap.js: add crossSourceSignals key + SLOW_KEYS entry
- cross-source-signals.ts: add getHydratedData('crossSourceSignals') bootstrap hydration
- seed script: fix isDeclinig typo, maritime theater ternary (Global->Indo-Pacific), displacement year dynamic
- commands.ts: add panel:cross-source-signals to cmd-k

* feat(cross-source-signals): redesign panel — severity bars, filled badges, icons, theater pills

- 4px severity accent bar on all signal rows (scannable without reading badges)
- Filled severity badges: CRITICAL=solid red/white, HIGH=faint red bg, MED=faint yellow bg
- Type badge emoji prefix:  composite, 🔴 geo-physical, 📡 EW, ✈️ military, 📊 market, ⚠️ geopolitical
- Composite card: full glow (box-shadow) instead of 3px left border only
- Theater pill with inline age: "Middle East · 8m ago"
- Contributor pills: individual chips instead of dot-separated string
- Pulsing dot on composite escalation banner

* fix(cross-source-signals): code review fixes — module-level Sets, signal cap, keyframe scoping, OREF expansion

- Replace per-call Array literals in list-cross-source-signals.ts with module-level Set constants for O(1) lookups
- Add index-based fallback ID in normalizeSignal to avoid undefined ids
- Remove unused military:flights:stale:v1 from SOURCE_KEYS
- Add MAX_SIGNALS=30 cap before writing to Redis
- Expand extractOrefAlertCluster to any "do not travel" advisory (not just Israel)
- Add BASE_WEIGHT inline documentation explaining scoring scale
- Fix animation keyframe: move from setContent() <style> block to constructor (injected once), rename to cross-source-pulse-dot
- Fix GDELT extractor to read per-topic gdelt:intel:tone:{topic} keys with correct decline logic
- Fix isDeclinig typo, maritime dead ternary, and displacement year reference
2026-03-24 23:18:31 +04:00
..