176 lines
5.4 KiB
C#
176 lines
5.4 KiB
C#
// 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;
|
|
|
|
/// <summary>
|
|
/// Canonical event envelope for unified timeline.
|
|
/// </summary>
|
|
public sealed record TimelineEvent
|
|
{
|
|
/// <summary>
|
|
/// Deterministic event ID: SHA-256(correlation_id || t_hlc || service || kind)[0:32] as hex.
|
|
/// </summary>
|
|
[JsonPropertyName("event_id")]
|
|
public required string EventId { get; init; }
|
|
|
|
/// <summary>
|
|
/// HLC timestamp from StellaOps.HybridLogicalClock.
|
|
/// </summary>
|
|
[JsonPropertyName("t_hlc")]
|
|
public required HlcTimestamp THlc { get; init; }
|
|
|
|
/// <summary>
|
|
/// Wall-clock time (informational only).
|
|
/// </summary>
|
|
[JsonPropertyName("ts_wall")]
|
|
public required DateTimeOffset TsWall { get; init; }
|
|
|
|
/// <summary>
|
|
/// Service name (e.g., "Scheduler", "AirGap", "Attestor").
|
|
/// </summary>
|
|
[JsonPropertyName("service")]
|
|
public required string Service { get; init; }
|
|
|
|
/// <summary>
|
|
/// W3C Trace Context traceparent.
|
|
/// </summary>
|
|
[JsonPropertyName("trace_parent")]
|
|
public string? TraceParent { get; init; }
|
|
|
|
/// <summary>
|
|
/// Correlation ID linking related events.
|
|
/// </summary>
|
|
[JsonPropertyName("correlation_id")]
|
|
public required string CorrelationId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Event kind (ENQUEUE, EXECUTE, EMIT, etc.).
|
|
/// </summary>
|
|
[JsonPropertyName("kind")]
|
|
public required string Kind { get; init; }
|
|
|
|
/// <summary>
|
|
/// RFC 8785 canonicalized JSON payload.
|
|
/// </summary>
|
|
[JsonPropertyName("payload")]
|
|
public required string Payload { get; init; }
|
|
|
|
/// <summary>
|
|
/// SHA-256 digest of Payload.
|
|
/// </summary>
|
|
[JsonPropertyName("payload_digest")]
|
|
public required byte[] PayloadDigest { get; init; }
|
|
|
|
/// <summary>
|
|
/// Engine version for reproducibility.
|
|
/// </summary>
|
|
[JsonPropertyName("engine_version")]
|
|
public required EngineVersionRef EngineVersion { get; init; }
|
|
|
|
/// <summary>
|
|
/// Optional DSSE signature.
|
|
/// </summary>
|
|
[JsonPropertyName("dsse_sig")]
|
|
public string? DsseSig { get; init; }
|
|
|
|
/// <summary>
|
|
/// Schema version (current: 1).
|
|
/// </summary>
|
|
[JsonPropertyName("schema_version")]
|
|
public int SchemaVersion { get; init; } = 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Engine version reference for reproducibility tracking.
|
|
/// </summary>
|
|
/// <param name="EngineName">The name of the engine/service.</param>
|
|
/// <param name="Version">The version string.</param>
|
|
/// <param name="SourceDigest">SHA-256 digest of the source or assembly.</param>
|
|
public sealed record EngineVersionRef(
|
|
[property: JsonPropertyName("engine_name")] string EngineName,
|
|
[property: JsonPropertyName("version")] string Version,
|
|
[property: JsonPropertyName("source_digest")] string SourceDigest)
|
|
{
|
|
/// <summary>
|
|
/// Creates an EngineVersionRef from the specified assembly metadata.
|
|
/// </summary>
|
|
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<AssemblyMetadataAttribute>()
|
|
.FirstOrDefault(a => a.Key == "SourceDigest")?.Value
|
|
?? "unknown";
|
|
|
|
return new EngineVersionRef(name.Name ?? "Unknown", version, sourceDigest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an EngineVersionRef from the entry assembly.
|
|
/// </summary>
|
|
public static EngineVersionRef FromEntryAssembly()
|
|
{
|
|
var assembly = Assembly.GetEntryAssembly()
|
|
?? throw new InvalidOperationException("No entry assembly found");
|
|
return FromAssembly(assembly);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pending event for batch emission.
|
|
/// </summary>
|
|
/// <param name="CorrelationId">Correlation ID linking related events.</param>
|
|
/// <param name="Kind">Event kind (ENQUEUE, EXECUTE, etc.).</param>
|
|
/// <param name="Payload">Event payload object.</param>
|
|
public sealed record PendingEvent(
|
|
string CorrelationId,
|
|
string Kind,
|
|
object Payload);
|
|
|
|
/// <summary>
|
|
/// Standard event kinds used across StellaOps services.
|
|
/// </summary>
|
|
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";
|
|
}
|