< Summary

Information
Class: AsiBackbone.Core.Emissions.GovernanceEmissionEnvelope
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Emissions/GovernanceEmissionEnvelope.cs
Line coverage
100%
Covered lines: 156
Uncovered lines: 0
Coverable lines: 156
Total lines: 403
Line coverage: 100%
Branch coverage
88%
Covered branches: 39
Total branches: 44
Branch coverage: 88.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%88100%
get_HasCorrelation()100%44100%
get_HasMetadata()100%11100%
Create(...)83.33%66100%
FromDecisionReceipt(...)50%22100%
FromLifecycleEvent(...)50%22100%
NormalizeIdentifier(...)100%22100%
NormalizeOptional(...)100%22100%
NormalizeNonNegative(...)100%22100%
NormalizeMetadata(...)87.5%1616100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Emissions/GovernanceEmissionEnvelope.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2using AsiBackbone.Core.Audit;
 3using AsiBackbone.Core.Serialization;
 4using AsiBackbone.Core.Signing;
 5
 6namespace AsiBackbone.Core.Emissions;
 7
 8/// <summary>
 9/// Represents a provider-neutral governance emission envelope that can be handed to outbox storage or downstream provid
 10/// </summary>
 11/// <remarks>
 12/// The envelope carries minimized governance context and safe diagnostics. It does not contain provider SDK payloads, c
 13/// </remarks>
 14public sealed class GovernanceEmissionEnvelope
 15{
 416    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 417        new ReadOnlyDictionary<string, string>(
 418            new Dictionary<string, string>(StringComparer.Ordinal));
 19
 97020    private GovernanceEmissionEnvelope(
 97021        string envelopeId,
 97022        string schemaVersion,
 97023        GovernanceEmissionEventType eventType,
 97024        string? eventId,
 97025        DateTimeOffset occurredUtc,
 97026        DateTimeOffset createdUtc,
 97027        string? correlationId,
 97028        string? decisionReceiptId,
 97029        DecisionReceiptLifecycleStage? lifecycleStage,
 97030        string? policyVersion,
 97031        string? policyHash,
 97032        string? traceId,
 97033        string? spanId,
 97034        string? parentSpanId,
 97035        string? operationName,
 97036        string? outcome,
 97037        string? actorId,
 97038        string? emitterStatus,
 97039        string? emitterProvider,
 97040        long? outboxSequence,
 97041        string? gatewayExecutionId,
 97042        string? decisionStage,
 97043        GovernanceEmissionPayload? payload,
 97044        IReadOnlyDictionary<string, string> metadata)
 45    {
 97046        ArgumentException.ThrowIfNullOrWhiteSpace(envelopeId);
 47
 97048        if (!Enum.IsDefined(eventType))
 49        {
 150            throw new ArgumentOutOfRangeException(nameof(eventType), eventType, "Governance emission event type must be 
 51        }
 52
 96953        if (lifecycleStage.HasValue && !Enum.IsDefined(lifecycleStage.Value))
 54        {
 155            throw new ArgumentOutOfRangeException(nameof(lifecycleStage), lifecycleStage, "Lifecycle stage must be defin
 56        }
 57
 96858        EnvelopeId = envelopeId.Trim();
 96859        SchemaVersion = GovernanceSchemaVersions.Normalize(schemaVersion);
 96860        EventType = eventType;
 96861        EventId = NormalizeOptional(eventId);
 96862        OccurredUtc = occurredUtc.ToUniversalTime();
 96863        CreatedUtc = createdUtc.ToUniversalTime();
 96864        CorrelationId = NormalizeOptional(correlationId);
 96865        DecisionReceiptId = NormalizeOptional(decisionReceiptId);
 96866        LifecycleStage = lifecycleStage;
 96867        LifecycleStageSequence = lifecycleStage.HasValue ? (int)lifecycleStage.Value : null;
 96868        PolicyVersion = NormalizeOptional(policyVersion);
 96869        PolicyHash = NormalizeOptional(policyHash);
 96870        TraceId = NormalizeOptional(traceId);
 96871        SpanId = NormalizeOptional(spanId);
 96872        ParentSpanId = NormalizeOptional(parentSpanId);
 96873        OperationName = NormalizeOptional(operationName);
 96874        Outcome = NormalizeOptional(outcome);
 96875        ActorId = NormalizeOptional(actorId);
 96876        EmitterStatus = NormalizeOptional(emitterStatus);
 96877        EmitterProvider = NormalizeOptional(emitterProvider);
 96878        OutboxSequence = NormalizeNonNegative(outboxSequence, nameof(outboxSequence));
 96779        GatewayExecutionId = NormalizeOptional(gatewayExecutionId);
 96780        DecisionStage = NormalizeOptional(decisionStage);
 96781        Payload = payload;
 96782        Metadata = metadata;
 96783    }
 84
 85    /// <summary>
 86    /// Gets the stable envelope identifier.
 87    /// </summary>
 88    public string EnvelopeId { get; }
 89
 90    /// <summary>
 91    /// Gets the schema version for this provider-neutral envelope shape.
 92    /// </summary>
 93    public string SchemaVersion { get; }
 94
 95    /// <summary>
 96    /// Gets the provider-neutral event category.
 97    /// </summary>
 98    public GovernanceEmissionEventType EventType { get; }
 99
 100    /// <summary>
 101    /// Gets the source governance event identifier, when available.
 102    /// </summary>
 103    public string? EventId { get; }
 104
 105    /// <summary>
 106    /// Gets the UTC timestamp when the source governance event occurred.
 107    /// </summary>
 108    public DateTimeOffset OccurredUtc { get; }
 109
 110    /// <summary>
 111    /// Gets the UTC timestamp when this emission envelope was created.
 112    /// </summary>
 113    public DateTimeOffset CreatedUtc { get; }
 114
 115    /// <summary>
 116    /// Gets the correlation identifier that links the emission to the host workflow, when available.
 117    /// </summary>
 118    public string? CorrelationId { get; }
 119
 120    /// <summary>
 121    /// Gets the decision receipt identifier linked to this emission, when available.
 122    /// </summary>
 123    public string? DecisionReceiptId { get; }
 124
 125    /// <summary>
 126    /// Gets the decision receipt lifecycle stage linked to this emission, when available.
 127    /// </summary>
 128    public DecisionReceiptLifecycleStage? LifecycleStage { get; }
 129
 130    /// <summary>
 131    /// Gets the stable lifecycle stage sequence value, when a lifecycle stage is supplied.
 132    /// </summary>
 133    public int? LifecycleStageSequence { get; }
 134
 135    /// <summary>
 136    /// Gets the policy version associated with the source governance event, when available.
 137    /// </summary>
 138    public string? PolicyVersion { get; }
 139
 140    /// <summary>
 141    /// Gets the policy hash associated with the source governance event, when available.
 142    /// </summary>
 143    public string? PolicyHash { get; }
 144
 145    /// <summary>
 146    /// Gets the trace identifier associated with the source governance event, when available.
 147    /// </summary>
 148    public string? TraceId { get; }
 149
 150    /// <summary>
 151    /// Gets the span identifier associated with the source governance event, when available.
 152    /// </summary>
 153    public string? SpanId { get; }
 154
 155    /// <summary>
 156    /// Gets the parent span identifier associated with the source governance event, when available.
 157    /// </summary>
 158    public string? ParentSpanId { get; }
 159
 160    /// <summary>
 161    /// Gets the operation name associated with the source governance event, when available.
 162    /// </summary>
 163    public string? OperationName { get; }
 164
 165    /// <summary>
 166    /// Gets the outcome associated with the source governance event, when available.
 167    /// </summary>
 168    public string? Outcome { get; }
 169
 170    /// <summary>
 171    /// Gets the actor identifier associated with the source governance event, when available.
 172    /// </summary>
 173    public string? ActorId { get; }
 174
 175    /// <summary>
 176    /// Gets the provider-neutral emitter status, when available.
 177    /// </summary>
 178    public string? EmitterStatus { get; }
 179
 180    /// <summary>
 181    /// Gets the provider-neutral emitter provider name, when available.
 182    /// </summary>
 183    public string? EmitterProvider { get; }
 184
 185    /// <summary>
 186    /// Gets the outbox sequence associated with the emission, when available.
 187    /// </summary>
 188    public long? OutboxSequence { get; }
 189
 190    /// <summary>
 191    /// Gets the gateway execution identifier associated with the emission, when available.
 192    /// </summary>
 193    public string? GatewayExecutionId { get; }
 194
 195    /// <summary>
 196    /// Gets the provider-neutral decision stage associated with the emission, when available.
 197    /// </summary>
 198    public string? DecisionStage { get; }
 199
 200    /// <summary>
 201    /// Gets the minimized provider-neutral payload descriptor, when available.
 202    /// </summary>
 203    public GovernanceEmissionPayload? Payload { get; }
 204
 205    /// <summary>
 206    /// Gets minimized provider-neutral metadata.
 207    /// </summary>
 208    public IReadOnlyDictionary<string, string> Metadata { get; }
 209
 210    /// <summary>
 211    /// Gets a value indicating whether correlation metadata is available.
 212    /// </summary>
 40213    public bool HasCorrelation => CorrelationId is not null || TraceId is not null || DecisionReceiptId is not null;
 214
 215    /// <summary>
 216    /// Gets a value indicating whether envelope metadata is present.
 217    /// </summary>
 37218    public bool HasMetadata => Metadata.Count > 0;
 219
 220    /// <summary>
 221    /// Creates a provider-neutral governance emission envelope.
 222    /// </summary>
 223    public static GovernanceEmissionEnvelope Create(
 224        GovernanceEmissionEventType eventType,
 225        string? eventId = null,
 226        DateTimeOffset? occurredUtc = null,
 227        string? envelopeId = null,
 228        DateTimeOffset? createdUtc = null,
 229        string? schemaVersion = null,
 230        string? correlationId = null,
 231        string? decisionReceiptId = null,
 232        DecisionReceiptLifecycleStage? lifecycleStage = null,
 233        string? policyVersion = null,
 234        string? policyHash = null,
 235        string? traceId = null,
 236        string? spanId = null,
 237        string? parentSpanId = null,
 238        string? operationName = null,
 239        string? outcome = null,
 240        string? actorId = null,
 241        string? emitterStatus = null,
 242        string? emitterProvider = null,
 243        long? outboxSequence = null,
 244        string? gatewayExecutionId = null,
 245        string? decisionStage = null,
 246        GovernanceEmissionPayload? payload = null,
 247        IReadOnlyDictionary<string, string>? metadata = null)
 248    {
 954249        return new GovernanceEmissionEnvelope(
 954250            NormalizeIdentifier(envelopeId),
 954251            schemaVersion ?? GovernanceSchemaVersions.StableArtifactsV1,
 954252            eventType,
 954253            eventId,
 954254            occurredUtc ?? DateTimeOffset.UtcNow,
 954255            createdUtc ?? DateTimeOffset.UtcNow,
 954256            correlationId,
 954257            decisionReceiptId,
 954258            lifecycleStage,
 954259            policyVersion,
 954260            policyHash,
 954261            traceId,
 954262            spanId,
 954263            parentSpanId,
 954264            operationName,
 954265            outcome,
 954266            actorId,
 954267            emitterStatus,
 954268            emitterProvider,
 954269            outboxSequence,
 954270            gatewayExecutionId,
 954271            decisionStage,
 954272            payload,
 954273            NormalizeMetadata(metadata));
 274    }
 275
 276    /// <summary>
 277    /// Creates a provider-neutral governance emission envelope from a decision receipt.
 278    /// </summary>
 279    public static GovernanceEmissionEnvelope FromDecisionReceipt(
 280        IDecisionReceipt receipt,
 281        GovernanceEmissionEventType eventType = GovernanceEmissionEventType.DecisionReceipt,
 282        string? envelopeId = null,
 283        DateTimeOffset? createdUtc = null,
 284        GovernanceEmissionPayload? payload = null,
 285        IReadOnlyDictionary<string, string>? metadata = null)
 286    {
 2287        ArgumentNullException.ThrowIfNull(receipt);
 288
 2289        return new GovernanceEmissionEnvelope(
 2290            NormalizeIdentifier(envelopeId),
 2291            receipt.SchemaVersion,
 2292            eventType,
 2293            receipt.EventId,
 2294            receipt.OccurredUtc,
 2295            createdUtc ?? DateTimeOffset.UtcNow,
 2296            receipt.CorrelationId,
 2297            receipt.DecisionReceiptId,
 2298            null,
 2299            receipt.PolicyVersion,
 2300            receipt.PolicyHash,
 2301            receipt.TraceId,
 2302            receipt.SpanId,
 2303            receipt.ParentSpanId,
 2304            receipt.OperationName,
 2305            receipt.Outcome,
 2306            receipt.ActorId,
 2307            receipt.EmitterStatus,
 2308            receipt.EmitterProvider,
 2309            receipt.OutboxSequence,
 2310            receipt.GatewayExecutionId,
 2311            receipt.DecisionStage,
 2312            payload,
 2313            NormalizeMetadata(receipt.Metadata, metadata));
 314    }
 315
 316    /// <summary>
 317    /// Creates a provider-neutral governance emission envelope from an decision receipt lifecycle event.
 318    /// </summary>
 319    public static GovernanceEmissionEnvelope FromLifecycleEvent(
 320        DecisionReceiptLifecycleEvent lifecycleEvent,
 321        string? envelopeId = null,
 322        DateTimeOffset? createdUtc = null,
 323        GovernanceEmissionPayload? payload = null,
 324        IReadOnlyDictionary<string, string>? metadata = null)
 325    {
 14326        ArgumentNullException.ThrowIfNull(lifecycleEvent);
 327
 14328        return new GovernanceEmissionEnvelope(
 14329            NormalizeIdentifier(envelopeId),
 14330            GovernanceSchemaVersions.StableArtifactsV1,
 14331            GovernanceEmissionEventType.AuditLifecycle,
 14332            lifecycleEvent.EventId,
 14333            lifecycleEvent.OccurredUtc,
 14334            createdUtc ?? DateTimeOffset.UtcNow,
 14335            lifecycleEvent.CorrelationId,
 14336            lifecycleEvent.DecisionReceiptId,
 14337            lifecycleEvent.Stage,
 14338            null,
 14339            null,
 14340            lifecycleEvent.TraceId,
 14341            null,
 14342            null,
 14343            lifecycleEvent.OperationName,
 14344            lifecycleEvent.Outcome,
 14345            null,
 14346            null,
 14347            null,
 14348            null,
 14349            null,
 14350            CanonicalEnumWireNames.ForLifecycleStage(lifecycleEvent.Stage),
 14351            payload,
 14352            NormalizeMetadata(lifecycleEvent.Metadata, metadata));
 353    }
 354
 355    private static string NormalizeIdentifier(string? identifier)
 356    {
 970357        return string.IsNullOrWhiteSpace(identifier)
 970358            ? Guid.NewGuid().ToString("N")
 970359            : identifier.Trim();
 360    }
 361
 362    private static string? NormalizeOptional(string? value)
 363    {
 14518364        return string.IsNullOrWhiteSpace(value)
 14518365            ? null
 14518366            : value.Trim();
 367    }
 368
 369    private static long? NormalizeNonNegative(long? value, string parameterName)
 370    {
 968371        return value < 0
 968372            ? throw new ArgumentOutOfRangeException(parameterName, value, "Value must be greater than or equal to zero."
 968373            : value;
 374    }
 375
 376    private static IReadOnlyDictionary<string, string> NormalizeMetadata(
 377        params IReadOnlyDictionary<string, string>?[] metadataSets)
 378    {
 970379        Dictionary<string, string> normalizedMetadata = new(StringComparer.Ordinal);
 380
 3912381        foreach (IReadOnlyDictionary<string, string>? metadata in metadataSets)
 382        {
 986383            if (metadata is null || metadata.Count == 0)
 384            {
 385                continue;
 386            }
 387
 830388            foreach (KeyValuePair<string, string> item in metadata)
 389            {
 243390                if (string.IsNullOrWhiteSpace(item.Key))
 391                {
 392                    continue;
 393                }
 394
 241395                normalizedMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 396            }
 397        }
 398
 970399        return normalizedMetadata.Count == 0
 970400            ? EmptyMetadata
 970401            : new ReadOnlyDictionary<string, string>(normalizedMetadata);
 402    }
 403}

Methods/Properties

.cctor()
.ctor(System.String,System.String,AsiBackbone.Core.Emissions.GovernanceEmissionEventType,System.String,System.DateTimeOffset,System.DateTimeOffset,System.String,System.String,System.Nullable`1<AsiBackbone.Core.Audit.DecisionReceiptLifecycleStage>,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable`1<System.Int64>,System.String,System.String,AsiBackbone.Core.Emissions.GovernanceEmissionPayload,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
get_HasCorrelation()
get_HasMetadata()
Create(AsiBackbone.Core.Emissions.GovernanceEmissionEventType,System.String,System.Nullable`1<System.DateTimeOffset>,System.String,System.Nullable`1<System.DateTimeOffset>,System.String,System.String,System.String,System.Nullable`1<AsiBackbone.Core.Audit.DecisionReceiptLifecycleStage>,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Nullable`1<System.Int64>,System.String,System.String,AsiBackbone.Core.Emissions.GovernanceEmissionPayload,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
FromDecisionReceipt(AsiBackbone.Core.Audit.IDecisionReceipt,AsiBackbone.Core.Emissions.GovernanceEmissionEventType,System.String,System.Nullable`1<System.DateTimeOffset>,AsiBackbone.Core.Emissions.GovernanceEmissionPayload,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
FromLifecycleEvent(AsiBackbone.Core.Audit.DecisionReceiptLifecycleEvent,System.String,System.Nullable`1<System.DateTimeOffset>,AsiBackbone.Core.Emissions.GovernanceEmissionPayload,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
NormalizeIdentifier(System.String)
NormalizeOptional(System.String)
NormalizeNonNegative(System.Nullable`1<System.Int64>,System.String)
NormalizeMetadata(System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>[])