signals.fact.updated Event Contract (SIGNALS-24-005)

Audience: Signals Guild, Policy Engine and Notifications consumers, Console integrators.

Purpose: Define the durable event-bus contract that the Signals module emits when a fact changes. This replaces the in-memory logger used during early development so reachability caches can be invalidated and downstream consumers (Policy Engine, Notifications, Console) can subscribe deterministically.

When a callgraph, runtime, reachability, or signal fact changes, Signals publishes a small, content-addressed envelope. Consumers fetch the full fact body from CAS by digest rather than receiving large payloads inline, keeping the bus lightweight and the contract stable.

Topic / channel

Message envelope

{
  "event_id": "uuid-v4",                // stable across retries; used for idempotency
  "emitted_at": "2025-11-20T00:00:00Z", // UTC, RFC3339
  "tenant": "acme",                     // required; lower-case
  "subject_key": "sbom:sha256:…" ,       // subject of facts (asset, sbom, host). Deterministic model key.
  "fact_kind": "callgraph" | "runtime" | "reachability" | "signal", // enums mapped from Signals domain
  "fact_version": 1,                     // monotonically increasing per subject_key + fact_kind
  "digest": "sha256:…",                 // CAS digest of canonical fact document
  "content_type": "application/json",   // or application/vnd.stellaops.ndjson when chunked
  "producer": "StellaOps.Signals",      // emitting service
  "source": {
    "pipeline": "signals",             // consistent with Observability tags
    "release": "0.4.0-alpha"           // optional
  },
  "trace": {
    "trace_id": "…",                   // pass-through if available
    "span_id": "…"
  }
}

Routing / partitions

Consumer expectations

Security / air-gap posture

Provenance