// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Text.Json.Serialization;
using StellaOps.HybridLogicalClock;
namespace StellaOps.Eventing.Models;
///
/// Canonical event envelope for unified timeline.
///
public sealed record TimelineEvent
{
///
/// Deterministic event ID: SHA-256(correlation_id || t_hlc || service || kind)[0:32] as hex.
///
[JsonPropertyName("event_id")]
public required string EventId { get; init; }
///
/// HLC timestamp from StellaOps.HybridLogicalClock.
///
[JsonPropertyName("t_hlc")]
public required HlcTimestamp THlc { get; init; }
///
/// Wall-clock time (informational only).
///
[JsonPropertyName("ts_wall")]
public required DateTimeOffset TsWall { get; init; }
///
/// Service name (e.g., "Scheduler", "AirGap", "Attestor").
///
[JsonPropertyName("service")]
public required string Service { get; init; }
///
/// W3C Trace Context traceparent.
///
[JsonPropertyName("trace_parent")]
public string? TraceParent { get; init; }
///
/// Correlation ID linking related events.
///
[JsonPropertyName("correlation_id")]
public required string CorrelationId { get; init; }
///
/// Event kind (ENQUEUE, EXECUTE, EMIT, etc.).
///
[JsonPropertyName("kind")]
public required string Kind { get; init; }
///
/// RFC 8785 canonicalized JSON payload.
///
[JsonPropertyName("payload")]
public required string Payload { get; init; }
///
/// SHA-256 digest of Payload.
///
[JsonPropertyName("payload_digest")]
public required byte[] PayloadDigest { get; init; }
///
/// Engine version for reproducibility.
///
[JsonPropertyName("engine_version")]
public required EngineVersionRef EngineVersion { get; init; }
///
/// Optional DSSE signature.
///
[JsonPropertyName("dsse_sig")]
public string? DsseSig { get; init; }
///
/// Schema version (current: 1).
///
[JsonPropertyName("schema_version")]
public int SchemaVersion { get; init; } = 1;
}
///
/// Engine version reference for reproducibility tracking.
///
/// The name of the engine/service.
/// The version string.
/// SHA-256 digest of the source or assembly.
public sealed record EngineVersionRef(
[property: JsonPropertyName("engine_name")] string EngineName,
[property: JsonPropertyName("version")] string Version,
[property: JsonPropertyName("source_digest")] string SourceDigest)
{
///
/// Creates an EngineVersionRef from the specified assembly metadata.
///
public static EngineVersionRef FromAssembly(Assembly assembly)
{
ArgumentNullException.ThrowIfNull(assembly);
var name = assembly.GetName();
var version = name.Version?.ToString() ?? "0.0.0";
// Try to get source digest from assembly metadata
var sourceDigest = assembly
.GetCustomAttributes()
.FirstOrDefault(a => a.Key == "SourceDigest")?.Value
?? "unknown";
return new EngineVersionRef(name.Name ?? "Unknown", version, sourceDigest);
}
///
/// Creates an EngineVersionRef from the entry assembly.
///
public static EngineVersionRef FromEntryAssembly()
{
var assembly = Assembly.GetEntryAssembly()
?? throw new InvalidOperationException("No entry assembly found");
return FromAssembly(assembly);
}
}
///
/// Pending event for batch emission.
///
/// Correlation ID linking related events.
/// Event kind (ENQUEUE, EXECUTE, etc.).
/// Event payload object.
public sealed record PendingEvent(
string CorrelationId,
string Kind,
object Payload);
///
/// Standard event kinds used across StellaOps services.
///
public static class EventKinds
{
// Scheduler events
public const string Enqueue = "ENQUEUE";
public const string Dequeue = "DEQUEUE";
public const string Execute = "EXECUTE";
public const string Complete = "COMPLETE";
public const string Fail = "FAIL";
// AirGap events
public const string Import = "IMPORT";
public const string Export = "EXPORT";
public const string Merge = "MERGE";
public const string Conflict = "CONFLICT";
// Attestor events
public const string Attest = "ATTEST";
public const string Verify = "VERIFY";
// Policy events
public const string Evaluate = "EVALUATE";
public const string GatePass = "GATE_PASS";
public const string GateFail = "GATE_FAIL";
// VexLens events
public const string Consensus = "CONSENSUS";
public const string Override = "OVERRIDE";
// Generic events
public const string Emit = "EMIT";
public const string Ack = "ACK";
public const string Error = "ERR";
}