Skip to content

Signal

Definition

A Signal is an external (or computed) trigger that may warrant investigation — a DSCR breach, a utilization spike, a watchlist flag. It is anchored to a subject (the entity it concerns), carries a severity, and runs through its own disposition lifecycle. Signals are the most common entry point into an investigation: a signal-driven Insight names the Signal in its entry_context.trigger, and closing an investigation requires every linked Signal to be resolved or dismissed. Signals are never deleted — archiving is recorded as a dismissal with an audit marker, preserving the trail.

Canonical schema: cortex/docs/spec/des-objects.yml:578. Runtime model: cortex/cortex/models/intelligence.py:374. Command logic: cortex/cortex/signal.py (plus cortex/cortex/tools/signal.py). Persistence: a UDS DAO over the shared Elasticsearch intelligence index under the signal alias, id sig_ + 12 hex.

Lifecycle

status: new → acknowledged → investigating → {resolved | dismissed}. The transition map is SIGNAL_TRANSITIONS (signal.py:61):

  • new → {acknowledged, investigating, dismissed}
  • acknowledged → {investigating, dismissed}
  • investigating → {resolved, dismissed}
  • resolved, dismissed — terminal

Transitions happen through signal_acknowledge (new → acknowledged), signal_set_disposition (any valid edge, fully audited), and signal_archive (any non-terminal → dismissed plus an archive marker). Two edges auto-advance: starting an investigation moves a new/acknowledged Signal to investigating (insight.py:264), and attesting the Edition that closes the investigation auto-resolves the source Signal investigating → resolved (edition.py:1052).

Journey through the code

Creation enters via MCP create_signal (tools/signal.py:541) — which requires a subject, builds the source and subject, sets status = new, and writes Signal().update(uid=sig_…) — or via REST POST /signalcrud.signal_create (crud.py:119). Mutation goes through signal_acknowledge, signal_set_disposition, signal_archive, and signal_link_insight (signal.py:231 onward); each strips system fields, writes the update, and appends to metadata.status_history[]. When a Signal is linked to an Insight, the disposition/link change also writes a signal_disposition_set / signal_linked InsightEvent onto the Insight ledger.

Reads: REST GET /signal/{uid} and GET /signal/by-entity/{entity_id}. The monitor dashboard scans Signals to compute active-count KPIs (monitor_tools.py:141) — it reads them, it never emits them. _format_signal (signal.py:123) reshapes the Signal into the subject{name} form Beacon expects.

Data shape

Required (des-objects.yml:583): schema_version, signal_type (freeform), source (with type ∈ webhook | mcp | polling | internal | manual | computed), severity (critical | high | medium | low | info), subject (type + id + name), title, detected_at.

Key optional / computed: status (default new), description, expires_at (defaulted by signal type), confidence (0–1), metadata (status_history[], resolved_by_edition, resolved_by_insight, archive markers), related_signals[], linked_insight_ids[], acknowledged_by / acknowledged_at, acknowledgment_note, routing, visibility_context. Storage: intelligence index, signal alias; key queryable fields signal_id, status, severity, subject.id.

Invariants

  • Never deleted. Archiving = dismissed + marker; the audit trail is preserved (DES Invariant 2, signal.py:420).
  • Forward-only status with resolved / dismissed terminal; every status change is recorded in metadata.status_history[] with from/to/by/at/rationale.
  • A subject is required at creation — a Signal is always about something.
  • product.insight — Signals link bidirectionally with Insights (linked_insight_ids[]linked_signal_ids[]) and are the entry_context.trigger of signal-driven investigations.
  • product.edition — attesting an Edition auto-resolves the source Signal and back-references it via metadata.resolved_by_edition.
  • product.block — monitor Blocks aggregate over Signals for KPIs but do not create them.

Open questions

  • actor and source.type: computed. DES adds an actor object (who/what raised the Signal) and the computed source type; the runtime Signal model has no actor field yet.
  • suppressed status. It appears in the intelligence.yaml enum but is not in the enforced state machine — unreconciled.
  • Subject rename. REST subject_ref / display_name vs Beacon subject / name — flagged in the DES changelog, not yet unified.

Realized by: component.cortex.decision-evidence, component.cortex.intelligence, component.cortex.signal-lifecycle, component.parallax.adi-integration, component.parallax.signal-payload