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
This commit is contained in:
Elie Habib
2026-03-24 23:18:31 +04:00
committed by GitHub
parent f87c8c71c4
commit e548e6cca5
21 changed files with 1499 additions and 3 deletions

View File

@@ -555,6 +555,32 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/intelligence/v1/list-cross-source-signals:
get:
tags:
- IntelligenceService
summary: ListCrossSourceSignals
description: ListCrossSourceSignals returns cross-domain signals ranked by severity with composite escalation detection.
operationId: ListCrossSourceSignals
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListCrossSourceSignalsResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/intelligence/v1/list-market-implications:
get:
tags:
@@ -1641,6 +1667,90 @@ components:
format: double
description: Tone or volume value at this point.
description: GdeltTimelinePoint is a single data point in a tone or volume timeline.
ListCrossSourceSignalsRequest:
type: object
description: ListCrossSourceSignalsRequest has no required parameters (returns all signals).
ListCrossSourceSignalsResponse:
type: object
properties:
signals:
type: array
items:
$ref: '#/components/schemas/CrossSourceSignal'
evaluatedAt:
type: integer
format: int64
description: 'Timestamp when the aggregator last ran (Unix epoch milliseconds).. Warning: Values > 2^53 may lose precision in JavaScript'
compositeCount:
type: integer
format: int32
description: Total number of composite escalation zones detected.
description: ListCrossSourceSignalsResponse contains ranked cross-domain signals.
CrossSourceSignal:
type: object
properties:
id:
type: string
description: Unique signal identifier.
type:
type: string
enum:
- CROSS_SOURCE_SIGNAL_TYPE_UNSPECIFIED
- CROSS_SOURCE_SIGNAL_TYPE_COMPOSITE_ESCALATION
- CROSS_SOURCE_SIGNAL_TYPE_THERMAL_SPIKE
- CROSS_SOURCE_SIGNAL_TYPE_GPS_JAMMING
- CROSS_SOURCE_SIGNAL_TYPE_MILITARY_FLIGHT_SURGE
- CROSS_SOURCE_SIGNAL_TYPE_UNREST_SURGE
- CROSS_SOURCE_SIGNAL_TYPE_OREF_ALERT_CLUSTER
- CROSS_SOURCE_SIGNAL_TYPE_VIX_SPIKE
- CROSS_SOURCE_SIGNAL_TYPE_COMMODITY_SHOCK
- CROSS_SOURCE_SIGNAL_TYPE_CYBER_ESCALATION
- CROSS_SOURCE_SIGNAL_TYPE_SHIPPING_DISRUPTION
- CROSS_SOURCE_SIGNAL_TYPE_SANCTIONS_SURGE
- CROSS_SOURCE_SIGNAL_TYPE_EARTHQUAKE_SIGNIFICANT
- CROSS_SOURCE_SIGNAL_TYPE_RADIATION_ANOMALY
- CROSS_SOURCE_SIGNAL_TYPE_INFRASTRUCTURE_OUTAGE
- CROSS_SOURCE_SIGNAL_TYPE_WILDFIRE_ESCALATION
- CROSS_SOURCE_SIGNAL_TYPE_DISPLACEMENT_SURGE
- CROSS_SOURCE_SIGNAL_TYPE_FORECAST_DETERIORATION
- CROSS_SOURCE_SIGNAL_TYPE_MARKET_STRESS
- CROSS_SOURCE_SIGNAL_TYPE_WEATHER_EXTREME
- CROSS_SOURCE_SIGNAL_TYPE_MEDIA_TONE_DETERIORATION
- CROSS_SOURCE_SIGNAL_TYPE_RISK_SCORE_SPIKE
description: CrossSourceSignalType enumerates all monitored cross-domain signal categories.
theater:
type: string
description: Theater / geographic context (e.g. "Eastern Europe", "Red Sea", "Global Markets").
summary:
type: string
description: Human-readable summary of the signal.
severity:
type: string
enum:
- CROSS_SOURCE_SIGNAL_SEVERITY_UNSPECIFIED
- CROSS_SOURCE_SIGNAL_SEVERITY_LOW
- CROSS_SOURCE_SIGNAL_SEVERITY_MEDIUM
- CROSS_SOURCE_SIGNAL_SEVERITY_HIGH
- CROSS_SOURCE_SIGNAL_SEVERITY_CRITICAL
description: CrossSourceSignalSeverity indicates the urgency tier of a detected signal.
severityScore:
type: number
format: double
description: 'Raw severity score used for ranking (higher = more severe).. Warning: Values > 2^53 may lose precision in JavaScript'
detectedAt:
type: integer
format: int64
description: 'Detection timestamp (Unix epoch milliseconds).. Warning: Values > 2^53 may lose precision in JavaScript'
contributingTypes:
type: array
items:
type: string
description: 'For COMPOSITE_ESCALATION: list of contributing signal type names.'
signalCount:
type: integer
format: int32
description: 'For COMPOSITE_ESCALATION: number of co-firing signals in theater.'
description: CrossSourceSignal represents a single detected cross-domain signal event.
ListMarketImplicationsRequest:
type: object
ListMarketImplicationsResponse: