///|
/// The stable identity class of a resource observed by an incident event.
pub(all) enum ResourceKind {
Service
Instance
Host
Container
Config
Trace
Custom(String)
} derive(Debug, Eq, ToJson)
///|
/// A typed resource identity. The kind and identifier stay separate so that
/// an instance is not accidentally treated as a service with a similar name.
pub(all) struct ResourceRef {
kind : ResourceKind
id : String
attributes : Json
} derive(Debug, Eq, ToJson)
///|
/// Structured producer identity for a canonical event.
pub(all) struct TelemetrySource {
system : String
component : String
host : String?
instrumentation_scope : String?
} derive(Debug, Eq, ToJson)
///|
/// A stable event category independent from severity.
pub(all) enum EventCategory {
Change
Availability
Performance
Process
Other(String)
} derive(Debug, Eq, ToJson)
///|
/// The observed outcome of an event, when the source provides one.
pub(all) enum EventOutcome {
Success
Failure
Unknown
Other(String)
} derive(Debug, Eq, ToJson)
///|
/// Location and transformation information retained for every canonical event.
pub(all) struct EventProvenance {
evidence_id : String
path : String
line_number : Int?
byte_offset : Int?
byte_length : Int?
sha256 : String?
profile_id : String
profile_version : String
} derive(Debug, Eq, ToJson)
///|
/// A source event with stable semantics, resource identity, and provenance.
///
/// `raw_content` is never replaced by normalized text. `body` and
/// `attributes` preserve structured values for later rules and reports.
pub(all) struct CanonicalEvent {
event_id : String
event_time : NormalizedTimestamp?
observed_time : NormalizedTimestamp?
source : TelemetrySource
resource : ResourceRef?
category : EventCategory
event_type : String
action : String?
outcome : EventOutcome
severity : Severity?
body : Json
raw_content : String
attributes : Json
provenance : EventProvenance
} derive(Debug, Eq, ToJson)
///|
/// Converts a canonical event to the legacy timeline view without losing the
/// original body stored in `raw_content`.
pub fn CanonicalEvent::to_normalized_event(
self : CanonicalEvent,
) -> NormalizedEvent {
{
timestamp: self.event_time,
severity: self.severity,
source_id: normalize_source_id(
self.source.system,
self.source.component,
self.source.host,
),
raw_content: self.raw_content,
}
}
///|
fn legacy_event_semantics(kind : CorrelationKind) -> (EventCategory, String) {
match kind {
CorrelationKind::Change => (EventCategory::Change, "legacy.change")
CorrelationKind::Alert => (EventCategory::Availability, "legacy.alert")
CorrelationKind::Crash => (EventCategory::Process, "legacy.crash")
CorrelationKind::Other(value) =>
(EventCategory::Other(value), "legacy.other")
}
}
///|
/// Converts a legacy adapter result into the canonical event contract.
///
/// The bridge keeps the legacy source identifier, resource identity,
/// attributes, raw content, and evidence line. It supplies conservative
/// semantics for fields that the legacy mapping does not describe.
pub fn IncidentEvent::to_canonical_event(
self : IncidentEvent,
) -> CanonicalEvent {
let (category, event_type) = legacy_event_semantics(self.kind)
let source : TelemetrySource = {
system: self.normalized.source_id,
component: "",
host: None,
instrumentation_scope: Some("legacy-adapter"),
}
let resource = match self.resource_id {
Some(resource_id) =>
Some({
kind: ResourceKind::Custom("legacy"),
id: resource_id,
attributes: {},
})
None => None
}
canonicalize_incident_event(
self,
source,
resource,
category,
event_type,
None,
EventOutcome::Unknown,
None,
{
evidence_id: self.evidence.evidence_id,
path: self.evidence.evidence_id,
line_number: Some(self.evidence.line_number),
byte_offset: None,
byte_length: None,
sha256: None,
profile_id: "legacy-adapter",
profile_version: "1",
},
)
}
///|
/// Bridges the existing adapter result into the canonical model. Classification,
/// resource identity, source structure, and provenance are explicit inputs so
/// this bridge never guesses business semantics from a message.
pub fn canonicalize_incident_event(
event : IncidentEvent,
source : TelemetrySource,
resource : ResourceRef?,
category : EventCategory,
event_type : String,
action : String?,
outcome : EventOutcome,
observed_time : NormalizedTimestamp?,
provenance : EventProvenance,
) -> CanonicalEvent {
{
event_id: event.event_id,
event_time: event.normalized.timestamp,
observed_time,
source,
resource,
category,
event_type,
action,
outcome,
severity: event.normalized.severity,
body: ToJson::to_json(event.normalized.raw_content),
raw_content: event.normalized.raw_content,
attributes: event.attributes,
provenance,
}
}
///|
/// The semantic type of a graph edge produced by a rule or processor.
pub(all) enum RelationType {
SameResource
TemporalBefore
MatchedRule
AliasOf
AttributeMatch
Custom(String)
} derive(Debug, Eq, ToJson)
///|
/// Whether a relation is a directly observed fact or a rule-based hypothesis.
pub(all) enum RelationStatus {
Observed
Hypothesis
} derive(Debug, Eq, ToJson)
///|
/// An explainable edge between two canonical events.
pub(all) struct EvidenceRelation {
relation_id : String
relation_type : RelationType
from_event_id : String
to_event_id : String
rule_id : String?
resource_key : ResourceRef?
delta_seconds : Int?
evidence_refs : Array[EventProvenance]
explanation : String
status : RelationStatus
} derive(Debug, Eq, ToJson)
///|
/// A diagnostic emitted when an event or rule cannot be fully evaluated.
pub(all) struct GraphDiagnostic {
code : String
message : String
event_id : String?
provenance : EventProvenance?
} derive(Debug, Eq, ToJson)
///|
/// The deterministic graph consumed by timeline, finding, and report views.
pub(all) struct IncidentGraph {
nodes : Array[CanonicalEvent]
edges : Array[EvidenceRelation]
diagnostics : Array[GraphDiagnostic]
} derive(Debug, Eq, ToJson)
///|
/// Creates an empty graph for incremental processors.
pub fn empty_incident_graph() -> IncidentGraph {
{ nodes: [], edges: [], diagnostics: [], }
}