Files
worldmonitor/docs/api/InfrastructureService.openapi.yaml
Elie Habib 45f5e5a457 feat(forecast): AI Forecasts prediction module (#1579)
* feat(forecast): add AI Forecasts prediction module (Pro-tier)

MiroFish-inspired prediction engine that generates structured forecasts
across 6 domains (conflict, market, supply chain, political, military,
infrastructure) using existing WorldMonitor data streams.

- Proto definitions for ForecastService with GetForecasts RPC
- Dedicated seed script (seed-forecasts.mjs) with 6 domain detectors,
  cross-domain cascade resolver, prediction market calibration, and
  trend detection via prior snapshot comparison
- Premium-gated RPC handler (PREMIUM_RPC_PATHS enforcement)
- Lazy-loaded ForecastPanel with domain filters, probability bars,
  trend arrows, signal evidence, and cascade links
- Health monitoring integration (seed-meta freshness tracking)
- Refresh scheduler with API key guard

* test(forecast): add 47 unit tests for forecast detectors and utilities

Covers forecastId, normalize, resolveCascades, calibrateWithMarkets,
computeTrends, and smoke tests for all 6 domain detectors. Exports
testable functions from seed script with direct-run guard.

* fix(forecast): domain mismatch 'infra' vs 'infrastructure', add panel category

- Seed script used 'infra' but ForecastPanel filtered on 'infrastructure',
  causing Infra tab to show zero results
- Added 'forecast' to intelligence category in PANEL_CATEGORY_MAP

* fix(forecast): move CSS to one-time injection, improve type safety

- P2: Move style block from setContent to one-time document.head injection
  to prevent CSS accumulation on repeated renders
- P3: Replace +toFixed(3) with Math.round for readability in seed script
- P3: Use Forecast type instead of any[] in RPC handler filter

* fix(forecast): handle sebuf proto data shapes from Redis

Detectors now normalize CII scores from server-side proto format
(combinedScore, TREND_DIRECTION_RISING, region) to uniform shape.
Outage severity handles proto enum format (SEVERITY_LEVEL_HIGH).
Added confidence floor of 0.3 for single-source predictions.

Verified against live Redis: 2 predictions generated (Iran infra
shutdown, IL political instability).

* feat(forecast): unlock AI Forecasts on web, lock desktop only (trial)

- Remove forecast RPC from PREMIUM_RPC_PATHS (web access is free)
- Panel locked on desktop only (same as oref-sirens/telegram-intel)
- Remove API key guards from data-loader and refresh scheduler
- Web users get full access during trial period

* chore: regenerate proto types with make generate

Re-ran make generate after rebasing on main. Plugin v0.7.0 dropped
@ts-nocheck from output, added it back to all 50 generated files.
Fixed 4 type errors from proto codegen changes:
- MarketSource enum -> string union type
- TemporalAnomalyProto -> TemporalAnomaly rename
- webcam lastUpdated number -> string

* fix(forecast): use chokepoints v4 key, include ciiContribution in unrest

- P1: Switch chokepoints input from stale v2 to active v4 Redis key,
  matching bootstrap.js and cache-keys.ts
- P2: Add ciiContribution to unrest component fallback chain in
  normalizeCiiEntry so political detector reads the correct sebuf field

* feat(forecast): Phase 2 LLM scenario enrichment + confidence model

MiroFish-inspired enhancements:
- LLM scenario narratives via Groq/OpenRouter (narrative-only, no numeric
  adjustment). Evidence-grounded prompts with mandatory signal citation
  and few-shot examples from MiroFish's SECTION_SYSTEM_PROMPT_TEMPLATE.
- Top-4 predictions batched into single LLM call for cost efficiency.
- News context from newsInsights attached to all predictions for LLM
  prompt grounding (NOT in signals, cannot affect confidence).
- Deterministic confidence model: source diversity via SIGNAL_TO_SOURCE
  mapping (deduplicates cii+cii_delta, theater+indicators) + calibration
  agreement from prediction market drift. Floor 0.2, ceiling 1.0.
- Output validation: rejects scenarios without signal references.
- Truncated JSON repair for small model output.
- Structured JSON logging for LLM calls.
- Redis cache for LLM scenarios (1h TTL).
- 23 new tests (70 total), all passing.
- Live-tested: OpenRouter gemini-2.5-flash produces evidence-grounded
  scenario narratives from real WorldMonitor data.

* feat(forecast): Phase 3 multi-perspective scenarios, projections, data-driven cascades

MiroFish-inspired enhancements:
- Multi-perspective LLM analysis: top-2 predictions get strategic,
  regional, and contrarian viewpoints via combined LLM call
- Probability projections: domain-specific decay curves (h24/d7/d30)
  anchored to timeHorizon so probability equals projections[timeHorizon]
- Data-driven cascade rules: moved from hardcoded array to JSON config
  (scripts/data/cascade-rules.json) with schema validation, named
  predicate evaluators, unknown key rejection, and fallback to defaults
- 4 new cascade paths: infrastructure->supply_chain, infrastructure->market
  (both requiresSeverity:total), conflict->political, political->market
- Proto: added Perspectives and Projections messages to Forecast
- ForecastPanel: renders projections row and conditional perspectives toggle
- 89 tests (19 new), all passing
- Live-tested: OpenRouter produces perspectives from real data

* feat(forecast): Phase 4 data utilization + entity graph

Fixes data gaps that prevented 4 of 6 detectors from firing:
- Input normalizers: chokepoint v4 shape + GPS hexes-to-zones mapping
- Chokepoint warm-ping (production-only, requires WM_API_BASE_URL)
- Lowered CII conflict threshold from 70 to 60, gated on level=high|critical

4 new standalone detectors:
- UCDP conflict zones (10+ events per country)
- Cyber threat concentration (5+ threats per country)
- GPS jamming in maritime shipping zones (5 regions)
- Prediction markets as signals (60-90% probability markets)

Entity-relationship graph (file-based, 38 nodes):
- Countries, theaters, commodities, chokepoints, alliances
- Alias table resolves both ISO codes and display names
- Graph cascade discovery links predictions across entities

Result: 51 predictions (up from 1-2), spanning conflict, infrastructure,
and supply chain domains. 112 tests, all passing.

* fix(forecast): redis cache format, signal source mapping, type safety

Fresh-eyes audit fixes:
- BUG: redisSet used wrong Upstash API format (POST body with {value,ex}
  instead of command array ['SET',key,value,'EX',ttl]). LLM cache writes
  were silently failing, causing fresh LLM calls every run.
- BUG: prediction_market signal type missing from SIGNAL_TO_SOURCE,
  inflating confidence for market-derived predictions.
- CLEANUP: Remove unnecessary (f as any) casts in ForecastPanel since
  generated Forecast type already has projections/perspectives fields.
- CLEANUP: Bump health maxStaleMin from 60 to 90 to avoid false STALE
  alerts when LLM calls add latency to seed runs.

* feat(forecast): headline-entity matching with news corroboration signals

Uses entity graph aliases to match headlines to predictions by
country/theater (excludes commodity/infrastructure nodes to prevent
false positives). Predictions with matching headlines get a
news_corroboration signal visible in the panel.

Also fixes buildUserPrompt to merge unique headlines from ALL
predictions in the LLM batch (was only reading preds[0].newsContext).

Live-tested: 13 of 51 predictions now have corroborating headlines
(Iran, Israel, Syria, Ukraine, etc). 116 tests, all passing.

* feat(forecast): add country-codes.json for headline-entity matching

56 countries with ISO codes, full names, and scoring keywords (extracted
from src/config/countries.ts + UCDP-relevant additions). Used by
attachNewsContext for richer headline matching via getSearchTermsForRegion
which combines country-codes + entity graph + keyword aliases.

14/57 predictions now have news corroboration (limited by headline
coverage, not matching quality: only 8 headlines currently available).

* feat(forecast): read 300 headlines from news digest instead of 8

Read news:digest:v1:full:en (300 headlines across 16 categories) instead
of just news:insights:v1 topStories (8 headlines). Fallback to topStories
if digest is unavailable.

Result: news corroboration jumped from 25% to 64% (38/59 predictions).

* fix(forecast): handle parenthetical country names in headline matching

Strip suffixes like '(Zaire)', '(Burma)', '(Soviet Union)' from UCDP
region names before matching against country-codes.json. Also use
includes() for reverse name lookup to catch partial matches.

Corroboration: 64% -> 69% (41/59). Remaining 18 unmatched are countries
with no current English-language news coverage.

* fix(forecast): cache validated LLM output, add digest test, log cache errors

Fresh-eyes audit fixes:
- Combined LLM cache now stores only validated items (was caching raw
  unvalidated output, serving potentially invalid scenarios on cache hit)
- redisSet logs warnings on failure (was silently swallowing all errors)
- Added digest-based test for attachNewsContext (primary path was untested)
- Fixed test arity: attachNewsContext(preds, news, digest) with 3 params

* fix(forecast): remove dead confidenceFromSources, reduce warm-ping timeout

- P2: Remove confidenceFromSources (dead code, computeConfidence overwrites
  all initial confidence values). Inline the formula in original detectors.
- P3: Reduce warm-ping timeout from 30s to 15s (non-critical step)
- P3: Add trial status comment on forecast panel config

* fix(forecast): resolve ISO codes to country names, fix market detector, safe pre-push

P1 fixes from code review:
- CII ISO codes (IL, IR) now resolved to full country names (Israel, Iran)
  via country-codes.json. Prevents substring false positives (IL matching
  Chile) in event correlation. Uses word-boundary regex for matching.
- Market detector CII-to-theater mapping now uses entity graph traversal
  instead of broken theater-name substring matching. Iran correctly maps
  to Middle East theater via graph links.
- Pre-push hook no longer runs destructive git checkout on proto freshness
  failure. Reports mismatch and exits without modifying worktree.
2026-03-15 01:42:04 +04:00

642 lines
27 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
openapi: 3.1.0
info:
title: InfrastructureService API
version: 1.0.0
paths:
/api/infrastructure/v1/list-internet-outages:
get:
tags:
- InfrastructureService
summary: ListInternetOutages
description: ListInternetOutages retrieves detected internet outages from Cloudflare Radar.
operationId: ListInternetOutages
parameters:
- name: start
in: query
description: Start of time range (inclusive), Unix epoch milliseconds.
required: false
schema:
type: string
format: int64
- name: end
in: query
description: End of time range (inclusive), Unix epoch milliseconds.
required: false
schema:
type: string
format: int64
- name: page_size
in: query
description: Maximum items per page.
required: false
schema:
type: integer
format: int32
- name: cursor
in: query
description: Cursor for next page.
required: false
schema:
type: string
- name: country
in: query
description: Optional country filter (ISO 3166-1 alpha-2).
required: false
schema:
type: string
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListInternetOutagesResponse'
"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/infrastructure/v1/list-service-statuses:
get:
tags:
- InfrastructureService
summary: ListServiceStatuses
description: ListServiceStatuses retrieves operational status of monitored external services.
operationId: ListServiceStatuses
parameters:
- name: status
in: query
description: Optional status filter. Returns only services in this state.
required: false
schema:
type: string
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListServiceStatusesResponse'
"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/infrastructure/v1/get-temporal-baseline:
get:
tags:
- InfrastructureService
summary: GetTemporalBaseline
description: GetTemporalBaseline checks current activity count against stored baseline for anomaly detection.
operationId: GetTemporalBaseline
parameters:
- name: type
in: query
description: 'Activity type: "military_flights", "vessels", "protests", "news", "ais_gaps", "satellite_fires".'
required: false
schema:
type: string
- name: region
in: query
description: Geographic region key, defaults to "global".
required: false
schema:
type: string
- name: count
in: query
description: Current observed count to compare against baseline.
required: false
schema:
type: number
format: double
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetTemporalBaselineResponse'
"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/infrastructure/v1/record-baseline-snapshot:
post:
tags:
- InfrastructureService
summary: RecordBaselineSnapshot
description: RecordBaselineSnapshot batch-updates baseline statistics using Welford's online algorithm.
operationId: RecordBaselineSnapshot
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/RecordBaselineSnapshotRequest'
required: true
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/RecordBaselineSnapshotResponse'
"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/infrastructure/v1/get-cable-health:
get:
tags:
- InfrastructureService
summary: GetCableHealth
description: GetCableHealth computes health status for submarine cables from NGA maritime warning signals.
operationId: GetCableHealth
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetCableHealthResponse'
"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/infrastructure/v1/list-temporal-anomalies:
get:
tags:
- InfrastructureService
summary: ListTemporalAnomalies
description: ListTemporalAnomalies returns server-computed temporal anomalies for news and satellite_fires.
operationId: ListTemporalAnomalies
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListTemporalAnomaliesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Error:
type: object
properties:
message:
type: string
description: Error message (e.g., 'user not found', 'database connection failed')
description: Error is returned when a handler encounters an error. It contains a simple error message that the developer can customize.
FieldViolation:
type: object
properties:
field:
type: string
description: The field path that failed validation (e.g., 'user.email' for nested fields). For header validation, this will be the header name (e.g., 'X-API-Key')
description:
type: string
description: Human-readable description of the validation violation (e.g., 'must be a valid email address', 'required field missing')
required:
- field
- description
description: FieldViolation describes a single validation error for a specific field.
ValidationError:
type: object
properties:
violations:
type: array
items:
$ref: '#/components/schemas/FieldViolation'
description: List of validation violations
required:
- violations
description: ValidationError is returned when request validation fails. It contains a list of field violations describing what went wrong.
ListInternetOutagesRequest:
type: object
properties:
start:
type: integer
format: int64
description: 'Start of time range (inclusive), Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
end:
type: integer
format: int64
description: 'End of time range (inclusive), Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
pageSize:
type: integer
format: int32
description: Maximum items per page.
cursor:
type: string
description: Cursor for next page.
country:
type: string
description: Optional country filter (ISO 3166-1 alpha-2).
description: ListInternetOutagesRequest specifies filters for retrieving internet outages.
ListInternetOutagesResponse:
type: object
properties:
outages:
type: array
items:
$ref: '#/components/schemas/InternetOutage'
pagination:
$ref: '#/components/schemas/PaginationResponse'
description: ListInternetOutagesResponse contains internet outages matching the request.
InternetOutage:
type: object
properties:
id:
type: string
minLength: 1
description: Unique outage identifier.
title:
type: string
description: Outage title.
link:
type: string
description: URL to the outage report.
description:
type: string
description: Outage description.
detectedAt:
type: integer
format: int64
description: 'Detection time, as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
country:
type: string
description: Affected country (ISO 3166-1 alpha-2).
region:
type: string
description: Affected region within the country.
location:
$ref: '#/components/schemas/GeoCoordinates'
severity:
type: string
enum:
- OUTAGE_SEVERITY_UNSPECIFIED
- OUTAGE_SEVERITY_PARTIAL
- OUTAGE_SEVERITY_MAJOR
- OUTAGE_SEVERITY_TOTAL
description: |-
OutageSeverity represents the severity of an internet outage.
Maps to TS union: 'partial' | 'major' | 'total'.
categories:
type: array
items:
type: string
description: Affected infrastructure categories.
cause:
type: string
description: Root cause, if determined.
outageType:
type: string
description: Outage type classification.
endedAt:
type: integer
format: int64
description: 'End time of the outage, as Unix epoch milliseconds. Zero if ongoing.. Warning: Values > 2^53 may lose precision in JavaScript'
required:
- id
description: InternetOutage represents a detected internet outage event from Cloudflare Radar.
GeoCoordinates:
type: object
properties:
latitude:
type: number
maximum: 90
minimum: -90
format: double
description: Latitude in decimal degrees (-90 to 90).
longitude:
type: number
maximum: 180
minimum: -180
format: double
description: Longitude in decimal degrees (-180 to 180).
description: GeoCoordinates represents a geographic location using WGS84 coordinates.
PaginationResponse:
type: object
properties:
nextCursor:
type: string
description: Cursor for fetching the next page. Empty string indicates no more pages.
totalCount:
type: integer
format: int32
description: Total count of items matching the query, if known. Zero if the total is unknown.
description: PaginationResponse contains pagination metadata returned alongside list results.
ListServiceStatusesRequest:
type: object
properties:
status:
type: string
enum:
- SERVICE_OPERATIONAL_STATUS_UNSPECIFIED
- SERVICE_OPERATIONAL_STATUS_OPERATIONAL
- SERVICE_OPERATIONAL_STATUS_DEGRADED
- SERVICE_OPERATIONAL_STATUS_PARTIAL_OUTAGE
- SERVICE_OPERATIONAL_STATUS_MAJOR_OUTAGE
- SERVICE_OPERATIONAL_STATUS_MAINTENANCE
description: ServiceOperationalStatus represents the current status of a service.
description: ListServiceStatusesRequest specifies filters for retrieving service statuses.
ListServiceStatusesResponse:
type: object
properties:
statuses:
type: array
items:
$ref: '#/components/schemas/ServiceStatus'
description: ListServiceStatusesResponse contains service operational statuses.
ServiceStatus:
type: object
properties:
id:
type: string
description: Service identifier.
name:
type: string
description: Service display name.
status:
type: string
enum:
- SERVICE_OPERATIONAL_STATUS_UNSPECIFIED
- SERVICE_OPERATIONAL_STATUS_OPERATIONAL
- SERVICE_OPERATIONAL_STATUS_DEGRADED
- SERVICE_OPERATIONAL_STATUS_PARTIAL_OUTAGE
- SERVICE_OPERATIONAL_STATUS_MAJOR_OUTAGE
- SERVICE_OPERATIONAL_STATUS_MAINTENANCE
description: ServiceOperationalStatus represents the current status of a service.
description:
type: string
description: Status description.
url:
type: string
description: Service URL or homepage.
checkedAt:
type: integer
format: int64
description: 'Last status check time, as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
latencyMs:
type: integer
format: int32
description: Response latency in milliseconds.
description: ServiceStatus represents the operational status of a monitored external service.
GetTemporalBaselineRequest:
type: object
properties:
type:
type: string
minLength: 1
description: 'Activity type: "military_flights", "vessels", "protests", "news", "ais_gaps", "satellite_fires".'
region:
type: string
description: Geographic region key, defaults to "global".
count:
type: number
format: double
description: Current observed count to compare against baseline.
required:
- type
description: GetTemporalBaselineRequest checks current activity count against stored baseline.
GetTemporalBaselineResponse:
type: object
properties:
anomaly:
$ref: '#/components/schemas/BaselineAnomaly'
baseline:
$ref: '#/components/schemas/BaselineStats'
learning:
type: boolean
description: True if insufficient samples have been collected.
sampleCount:
type: integer
format: int32
description: Current number of samples stored.
samplesNeeded:
type: integer
format: int32
description: Minimum samples required before anomaly detection activates.
error:
type: string
description: Error message if request was invalid.
description: GetTemporalBaselineResponse returns anomaly info or learning status.
BaselineAnomaly:
type: object
properties:
zScore:
type: number
format: double
description: Number of standard deviations from the mean.
severity:
type: string
description: 'Severity label: "critical", "high", "medium", "normal".'
multiplier:
type: number
format: double
description: Ratio of current count to baseline mean.
description: BaselineAnomaly describes a detected deviation from historical baseline.
BaselineStats:
type: object
properties:
mean:
type: number
format: double
description: Running mean of observed counts.
stdDev:
type: number
format: double
description: Standard deviation derived from Welford's M2.
sampleCount:
type: integer
format: int32
description: Number of samples incorporated so far.
description: BaselineStats contains the running statistics for a baseline key.
RecordBaselineSnapshotRequest:
type: object
properties:
updates:
type: array
items:
$ref: '#/components/schemas/BaselineUpdate'
description: RecordBaselineSnapshotRequest batch-updates baselines using Welford's online algorithm.
BaselineUpdate:
type: object
properties:
type:
type: string
minLength: 1
description: Activity type key.
region:
type: string
description: Geographic region key, defaults to "global".
count:
type: number
format: double
description: Observed count value.
required:
- type
description: BaselineUpdate is a single metric observation to incorporate into the running baseline.
RecordBaselineSnapshotResponse:
type: object
properties:
updated:
type: integer
format: int32
description: Number of baselines that were written.
error:
type: string
description: Error message if the request was invalid.
description: RecordBaselineSnapshotResponse reports how many baselines were successfully updated.
GetCableHealthRequest:
type: object
description: GetCableHealthRequest requests the current health status of all monitored submarine cables.
GetCableHealthResponse:
type: object
properties:
generatedAt:
type: integer
format: int64
description: 'Generation timestamp, as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
cables:
type: object
additionalProperties:
$ref: '#/components/schemas/CableHealthRecord'
description: Health records keyed by cable identifier.
description: GetCableHealthResponse contains health status for submarine cables with active signals.
CablesEntry:
type: object
properties:
key:
type: string
value:
$ref: '#/components/schemas/CableHealthRecord'
CableHealthRecord:
type: object
properties:
status:
type: string
enum:
- CABLE_HEALTH_STATUS_UNSPECIFIED
- CABLE_HEALTH_STATUS_OK
- CABLE_HEALTH_STATUS_DEGRADED
- CABLE_HEALTH_STATUS_FAULT
description: CableHealthStatus represents the computed health status of a submarine cable.
score:
type: number
format: double
description: Composite health score (0.0 = healthy, 1.0 = confirmed fault).
confidence:
type: number
format: double
description: Confidence in the health assessment (0.01.0).
lastUpdated:
type: integer
format: int64
description: 'Last signal update time, as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
evidence:
type: array
items:
$ref: '#/components/schemas/CableHealthEvidence'
description: CableHealthRecord contains the computed health status and supporting evidence for a cable.
CableHealthEvidence:
type: object
properties:
source:
type: string
description: Evidence source (e.g. "NGA").
summary:
type: string
description: Human-readable summary of the evidence.
ts:
type: integer
format: int64
description: 'Evidence timestamp, as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
description: CableHealthEvidence represents a single piece of evidence supporting a health assessment.
ListTemporalAnomaliesRequest:
type: object
ListTemporalAnomaliesResponse:
type: object
properties:
anomalies:
type: array
items:
$ref: '#/components/schemas/TemporalAnomaly'
trackedTypes:
type: array
items:
type: string
computedAt:
type: string
TemporalAnomaly:
type: object
properties:
type:
type: string
region:
type: string
currentCount:
type: integer
format: int32
expectedCount:
type: integer
format: int32
zScore:
type: number
format: double
severity:
type: string
multiplier:
type: number
format: double
message:
type: string