< Summary

Information
Class: AsiBackbone.Core.Outbox.GovernanceOutboxEntry
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Outbox/GovernanceOutboxEntry.cs
Line coverage
100%
Covered lines: 249
Uncovered lines: 0
Coverable lines: 249
Total lines: 584
Line coverage: 100%
Branch coverage
92%
Covered branches: 87
Total branches: 94
Branch coverage: 92.5%
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%1414100%
get_IsDelivered()100%11100%
get_IsDeadLettered()100%11100%
get_HasMetadata()100%11100%
get_HasClaim()100%66100%
Create(...)100%22100%
Restore(...)100%11100%
IsRetryReady(...)93.75%1616100%
HasActiveClaim(...)75%44100%
CanBeClaimed(...)50%44100%
IsClaimedBy(...)100%44100%
MarkClaimed(...)87.5%88100%
ReleaseClaim(...)100%11100%
MarkDelivered(...)100%22100%
MarkFailed(...)100%22100%
MarkDeferred(...)100%22100%
MarkDeadLettered(...)100%22100%
Copy(...)100%22100%
NormalizeIdentifier(...)100%22100%
NormalizeOptional(...)100%22100%
MergeMetadata(...)100%88100%
NormalizeMetadata(...)85.71%1414100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Outbox/GovernanceOutboxEntry.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2using AsiBackbone.Core.Emissions;
 3
 4namespace AsiBackbone.Core.Outbox;
 5
 6/// <summary>
 7/// Represents a provider-neutral durable outbox entry for a governance emission envelope.
 8/// </summary>
 9/// <remarks>
 10/// Outbox entries are intended to be persisted before optional downstream provider delivery is attempted.
 11/// </remarks>
 12public sealed class GovernanceOutboxEntry
 13{
 14    private const int DefaultMaxRetryCount = 5;
 15
 316    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 317        new ReadOnlyDictionary<string, string>(
 318            new Dictionary<string, string>(StringComparer.Ordinal));
 19
 111420    private GovernanceOutboxEntry(
 111421        string outboxEntryId,
 111422        GovernanceEmissionEnvelope envelope,
 111423        GovernanceEmissionStatus status,
 111424        DateTimeOffset createdUtc,
 111425        DateTimeOffset updatedUtc,
 111426        int retryCount,
 111427        int maxRetryCount,
 111428        DateTimeOffset? nextRetryUtc,
 111429        GovernanceEmissionError? lastError,
 111430        string? providerName,
 111431        string? providerRecordId,
 111432        string? deadLetterReason,
 111433        IReadOnlyDictionary<string, string> metadata,
 111434        string? claimOwner,
 111435        string? claimToken,
 111436        DateTimeOffset? claimedUtc,
 111437        DateTimeOffset? claimExpiresUtc,
 111438        int claimAttemptCount)
 39    {
 111440        ArgumentException.ThrowIfNullOrWhiteSpace(outboxEntryId);
 111241        ArgumentNullException.ThrowIfNull(envelope);
 42
 111143        if (!Enum.IsDefined(status))
 44        {
 245            throw new ArgumentOutOfRangeException(nameof(status), status, "Outbox status must be defined.");
 46        }
 47
 110948        if (retryCount < 0)
 49        {
 250            throw new ArgumentOutOfRangeException(nameof(retryCount), retryCount, "Retry count must be greater than or e
 51        }
 52
 110753        if (maxRetryCount < 0)
 54        {
 355            throw new ArgumentOutOfRangeException(nameof(maxRetryCount), maxRetryCount, "Maximum retry count must be gre
 56        }
 57
 110458        if (claimAttemptCount < 0)
 59        {
 160            throw new ArgumentOutOfRangeException(nameof(claimAttemptCount), claimAttemptCount, "Claim attempt count mus
 61        }
 62
 110363        OutboxEntryId = outboxEntryId.Trim();
 110364        Envelope = envelope;
 110365        Status = status;
 110366        CreatedUtc = createdUtc.ToUniversalTime();
 110367        UpdatedUtc = updatedUtc.ToUniversalTime();
 110368        RetryCount = retryCount;
 110369        MaxRetryCount = maxRetryCount;
 110370        NextRetryUtc = nextRetryUtc?.ToUniversalTime();
 110371        LastError = lastError;
 110372        ProviderName = NormalizeOptional(providerName);
 110373        ProviderRecordId = NormalizeOptional(providerRecordId);
 110374        DeadLetterReason = NormalizeOptional(deadLetterReason);
 110375        Metadata = metadata;
 110376        ClaimOwner = NormalizeOptional(claimOwner);
 110377        ClaimToken = NormalizeOptional(claimToken);
 110378        ClaimedUtc = claimedUtc?.ToUniversalTime();
 110379        ClaimExpiresUtc = claimExpiresUtc?.ToUniversalTime();
 110380        ClaimAttemptCount = claimAttemptCount;
 110381    }
 82
 83    /// <summary>
 84    /// Gets the stable outbox entry identifier.
 85    /// </summary>
 86    public string OutboxEntryId { get; }
 87
 88    /// <summary>
 89    /// Gets the provider-neutral governance emission envelope being persisted for delivery.
 90    /// </summary>
 91    public GovernanceEmissionEnvelope Envelope { get; }
 92
 93    /// <summary>
 94    /// Gets the current provider-neutral outbox status.
 95    /// </summary>
 96    public GovernanceEmissionStatus Status { get; }
 97
 98    /// <summary>
 99    /// Gets the UTC timestamp when the outbox entry was created.
 100    /// </summary>
 101    public DateTimeOffset CreatedUtc { get; }
 102
 103    /// <summary>
 104    /// Gets the UTC timestamp when the outbox entry was last updated.
 105    /// </summary>
 106    public DateTimeOffset UpdatedUtc { get; }
 107
 108    /// <summary>
 109    /// Gets the number of failed or deferred delivery attempts recorded for this entry.
 110    /// </summary>
 111    public int RetryCount { get; }
 112
 113    /// <summary>
 114    /// Gets the persisted maximum retry count retained for storage compatibility.
 115    /// </summary>
 116    /// <remarks>
 117    /// Retry eligibility and threshold dead-lettering are controlled by <see cref="GovernanceOutboxOptions" />
 118    /// when the entry is processed by <see cref="GovernanceOutboxDrain" />.
 119    /// </remarks>
 120    public int MaxRetryCount { get; }
 121
 122    /// <summary>
 123    /// Gets the next UTC retry timestamp, when retry scheduling is active.
 124    /// </summary>
 125    public DateTimeOffset? NextRetryUtc { get; }
 126
 127    /// <summary>
 128    /// Gets the last provider-neutral emission error, when available.
 129    /// </summary>
 130    public GovernanceEmissionError? LastError { get; }
 131
 132    /// <summary>
 133    /// Gets the provider name associated with the most recent attempt, when available.
 134    /// </summary>
 135    public string? ProviderName { get; }
 136
 137    /// <summary>
 138    /// Gets the provider-side record identifier, when delivery returned one and it is safe to store.
 139    /// </summary>
 140    public string? ProviderRecordId { get; }
 141
 142    /// <summary>
 143    /// Gets the dead-letter reason, when the entry has reached a terminal dead-letter state.
 144    /// </summary>
 145    public string? DeadLetterReason { get; }
 146
 147    /// <summary>
 148    /// Gets minimized provider-neutral outbox metadata.
 149    /// </summary>
 150    public IReadOnlyDictionary<string, string> Metadata { get; }
 151
 152    /// <summary>
 153    /// Gets the current claim owner, when this row is leased by a worker.
 154    /// </summary>
 155    public string? ClaimOwner { get; }
 156
 157    /// <summary>
 158    /// Gets the opaque token for the current claim lease.
 159    /// </summary>
 160    public string? ClaimToken { get; }
 161
 162    /// <summary>
 163    /// Gets the UTC timestamp when the current claim was acquired.
 164    /// </summary>
 165    public DateTimeOffset? ClaimedUtc { get; }
 166
 167    /// <summary>
 168    /// Gets the UTC timestamp when the current claim lease expires.
 169    /// </summary>
 170    public DateTimeOffset? ClaimExpiresUtc { get; }
 171
 172    /// <summary>
 173    /// Gets the number of claim or reclaim attempts recorded for this entry.
 174    /// </summary>
 175    public int ClaimAttemptCount { get; }
 176
 177    /// <summary>
 178    /// Gets a value indicating whether this entry was delivered successfully.
 179    /// </summary>
 409180    public bool IsDelivered => Status is GovernanceEmissionStatus.Delivered;
 181
 182    /// <summary>
 183    /// Gets a value indicating whether this entry has reached a terminal dead-letter state.
 184    /// </summary>
 390185    public bool IsDeadLettered => Status is GovernanceEmissionStatus.DeadLettered;
 186
 187    /// <summary>
 188    /// Gets a value indicating whether metadata is present.
 189    /// </summary>
 38190    public bool HasMetadata => Metadata.Count > 0;
 191
 192    /// <summary>
 193    /// Gets a value indicating whether claim metadata is present.
 194    /// </summary>
 160195    public bool HasClaim => ClaimOwner is not null && ClaimToken is not null && ClaimedUtc.HasValue && ClaimExpiresUtc.H
 196
 197    /// <summary>
 198    /// Creates a pending durable outbox entry.
 199    /// </summary>
 200    public static GovernanceOutboxEntry Create(
 201        GovernanceEmissionEnvelope envelope,
 202        string? outboxEntryId = null,
 203        DateTimeOffset? createdUtc = null,
 204        int maxRetryCount = DefaultMaxRetryCount,
 205        IReadOnlyDictionary<string, string>? metadata = null)
 206    {
 347207        DateTimeOffset timestamp = createdUtc ?? DateTimeOffset.UtcNow;
 208
 347209        return new GovernanceOutboxEntry(
 347210            NormalizeIdentifier(outboxEntryId),
 347211            envelope,
 347212            GovernanceEmissionStatus.Pending,
 347213            timestamp,
 347214            timestamp,
 347215            retryCount: 0,
 347216            maxRetryCount,
 347217            nextRetryUtc: null,
 347218            lastError: null,
 347219            providerName: null,
 347220            providerRecordId: null,
 347221            deadLetterReason: null,
 347222            NormalizeMetadata(metadata),
 347223            claimOwner: null,
 347224            claimToken: null,
 347225            claimedUtc: null,
 347226            claimExpiresUtc: null,
 347227            claimAttemptCount: 0);
 228    }
 229
 230    /// <summary>
 231    /// Restores a durable outbox entry from provider-neutral storage.
 232    /// </summary>
 233    /// <remarks>
 234    /// This factory exists for storage adapters. It does not perform provider emission and does not add any provider de
 235    /// </remarks>
 236    public static GovernanceOutboxEntry Restore(
 237        GovernanceEmissionEnvelope envelope,
 238        GovernanceEmissionStatus status,
 239        string outboxEntryId,
 240        DateTimeOffset createdUtc,
 241        DateTimeOffset updatedUtc,
 242        int retryCount = 0,
 243        int maxRetryCount = DefaultMaxRetryCount,
 244        DateTimeOffset? nextRetryUtc = null,
 245        GovernanceEmissionError? lastError = null,
 246        string? providerName = null,
 247        string? providerRecordId = null,
 248        string? deadLetterReason = null,
 249        IReadOnlyDictionary<string, string>? metadata = null,
 250        string? claimOwner = null,
 251        string? claimToken = null,
 252        DateTimeOffset? claimedUtc = null,
 253        DateTimeOffset? claimExpiresUtc = null,
 254        int claimAttemptCount = 0)
 255    {
 563256        return new GovernanceOutboxEntry(
 563257            outboxEntryId,
 563258            envelope,
 563259            status,
 563260            createdUtc,
 563261            updatedUtc,
 563262            retryCount,
 563263            maxRetryCount,
 563264            nextRetryUtc,
 563265            lastError,
 563266            providerName,
 563267            providerRecordId,
 563268            deadLetterReason,
 563269            NormalizeMetadata(metadata),
 563270            claimOwner,
 563271            claimToken,
 563272            claimedUtc,
 563273            claimExpiresUtc,
 563274            claimAttemptCount);
 275    }
 276
 277    /// <summary>
 278    /// Determines whether the entry is ready for retry at the supplied UTC timestamp.
 279    /// </summary>
 280    public bool IsRetryReady(DateTimeOffset utcNow)
 281    {
 70282        return !IsDelivered && !IsDeadLettered && Status is GovernanceEmissionStatus.Deferred or GovernanceEmissionStatu
 283    }
 284
 285    /// <summary>
 286    /// Determines whether the entry has an active claim lease at the supplied UTC timestamp.
 287    /// </summary>
 288    public bool HasActiveClaim(DateTimeOffset utcNow)
 289    {
 87290        return HasClaim && ClaimExpiresUtc > utcNow.ToUniversalTime();
 291    }
 292
 293    /// <summary>
 294    /// Determines whether the entry may be claimed by a cooperating worker at the supplied UTC timestamp.
 295    /// </summary>
 296    public bool CanBeClaimed(DateTimeOffset utcNow)
 297    {
 85298        return !IsDelivered && !IsDeadLettered && !HasActiveClaim(utcNow);
 299    }
 300
 301    /// <summary>
 302    /// Determines whether the entry is still owned by the supplied claim token.
 303    /// </summary>
 304    public bool IsClaimedBy(GovernanceOutboxClaim claim)
 305    {
 80306        ArgumentNullException.ThrowIfNull(claim);
 307
 80308        return string.Equals(OutboxEntryId, claim.OutboxEntryId, StringComparison.Ordinal)
 80309            && string.Equals(ClaimOwner, claim.WorkerId, StringComparison.Ordinal)
 80310            && string.Equals(ClaimToken, claim.ClaimToken, StringComparison.Ordinal);
 311    }
 312
 313    /// <summary>
 314    /// Returns a claimed copy of this entry.
 315    /// </summary>
 316    public GovernanceOutboxEntry MarkClaimed(
 317        string claimOwner,
 318        string? claimToken = null,
 319        DateTimeOffset? claimedUtc = null,
 320        TimeSpan? leaseDuration = null)
 321    {
 45322        ArgumentException.ThrowIfNullOrWhiteSpace(claimOwner);
 323
 45324        DateTimeOffset normalizedClaimedUtc = (claimedUtc ?? DateTimeOffset.UtcNow).ToUniversalTime();
 45325        TimeSpan normalizedLeaseDuration = leaseDuration ?? GovernanceOutboxClaimRequest.DefaultLeaseDuration;
 326
 45327        return normalizedLeaseDuration <= TimeSpan.Zero
 45328            ? throw new ArgumentOutOfRangeException(nameof(leaseDuration), leaseDuration, "Lease duration must be greate
 45329            : Copy(
 45330            Status,
 45331            normalizedClaimedUtc,
 45332            RetryCount,
 45333            NextRetryUtc,
 45334            LastError,
 45335            ProviderName,
 45336            ProviderRecordId,
 45337            DeadLetterReason,
 45338            Metadata,
 45339            claimOwner.Trim(),
 45340            string.IsNullOrWhiteSpace(claimToken) ? Guid.NewGuid().ToString("N") : claimToken.Trim(),
 45341            normalizedClaimedUtc,
 45342            normalizedClaimedUtc.Add(normalizedLeaseDuration),
 45343            ClaimAttemptCount + 1);
 344    }
 345
 346    /// <summary>
 347    /// Returns a copy with claim lease fields cleared.
 348    /// </summary>
 349    public GovernanceOutboxEntry ReleaseClaim(DateTimeOffset? updatedUtc = null)
 350    {
 6351        return Copy(
 6352            Status,
 6353            updatedUtc,
 6354            RetryCount,
 6355            NextRetryUtc,
 6356            LastError,
 6357            ProviderName,
 6358            ProviderRecordId,
 6359            DeadLetterReason,
 6360            Metadata,
 6361            claimOwner: null,
 6362            claimToken: null,
 6363            claimedUtc: null,
 6364            claimExpiresUtc: null,
 6365            ClaimAttemptCount);
 366    }
 367
 368    /// <summary>
 369    /// Returns a delivered copy of this entry.
 370    /// </summary>
 371    public GovernanceOutboxEntry MarkDelivered(
 372        GovernanceEmissionResult result,
 373        DateTimeOffset? updatedUtc = null)
 374    {
 48375        ArgumentNullException.ThrowIfNull(result);
 376
 48377        return !result.IsSuccess
 48378            ? throw new ArgumentException("Delivered outbox transitions require a successful emission result.", nameof(r
 48379            : Copy(
 48380            GovernanceEmissionStatus.Delivered,
 48381            updatedUtc,
 48382            retryCount: RetryCount,
 48383            nextRetryUtc: null,
 48384            lastError: null,
 48385            providerName: result.ProviderName,
 48386            providerRecordId: result.ProviderRecordId,
 48387            deadLetterReason: null,
 48388            metadata: MergeMetadata(Metadata, result.Metadata),
 48389            claimOwner: null,
 48390            claimToken: null,
 48391            claimedUtc: null,
 48392            claimExpiresUtc: null,
 48393            ClaimAttemptCount);
 394    }
 395
 396    /// <summary>
 397    /// Returns a failed or retryable-failure copy of this entry.
 398    /// </summary>
 399    public GovernanceOutboxEntry MarkFailed(
 400        GovernanceEmissionError governanceEmissionError,
 401        DateTimeOffset? nextRetryUtc = null,
 402        DateTimeOffset? updatedUtc = null)
 403    {
 67404        ArgumentNullException.ThrowIfNull(governanceEmissionError);
 405
 67406        int nextRetryCount = RetryCount + 1;
 67407        GovernanceEmissionStatus nextStatus = governanceEmissionError.IsRetryable
 67408            ? GovernanceEmissionStatus.RetryableFailure
 67409            : GovernanceEmissionStatus.Failed;
 410
 67411        return Copy(
 67412            nextStatus,
 67413            updatedUtc,
 67414            nextRetryCount,
 67415            nextRetryUtc,
 67416            governanceEmissionError,
 67417            governanceEmissionError.ProviderName,
 67418            providerRecordId: null,
 67419            deadLetterReason: null,
 67420            Metadata,
 67421            claimOwner: null,
 67422            claimToken: null,
 67423            claimedUtc: null,
 67424            claimExpiresUtc: null,
 67425            ClaimAttemptCount);
 426    }
 427
 428    /// <summary>
 429    /// Returns a deferred copy of this entry.
 430    /// </summary>
 431    public GovernanceOutboxEntry MarkDeferred(
 432        GovernanceEmissionError? governanceEmissionError = null,
 433        DateTimeOffset? nextRetryUtc = null,
 434        DateTimeOffset? updatedUtc = null)
 435    {
 22436        return Copy(
 22437            GovernanceEmissionStatus.Deferred,
 22438            updatedUtc,
 22439            retryCount: RetryCount,
 22440            nextRetryUtc,
 22441            governanceEmissionError,
 22442            governanceEmissionError?.ProviderName,
 22443            providerRecordId: null,
 22444            deadLetterReason: null,
 22445            metadata: Metadata,
 22446            claimOwner: null,
 22447            claimToken: null,
 22448            claimedUtc: null,
 22449            claimExpiresUtc: null,
 22450            ClaimAttemptCount);
 451    }
 452
 453    /// <summary>
 454    /// Returns a dead-lettered copy of this entry.
 455    /// </summary>
 456    public GovernanceOutboxEntry MarkDeadLettered(
 457        GovernanceEmissionError governanceEmissionError,
 458        string? deadLetterReason = null,
 459        DateTimeOffset? updatedUtc = null)
 460    {
 20461        ArgumentNullException.ThrowIfNull(governanceEmissionError);
 462
 20463        return Copy(
 20464            GovernanceEmissionStatus.DeadLettered,
 20465            updatedUtc,
 20466            retryCount: RetryCount,
 20467            nextRetryUtc: null,
 20468            lastError: governanceEmissionError,
 20469            providerName: governanceEmissionError.ProviderName,
 20470            providerRecordId: null,
 20471            deadLetterReason: deadLetterReason ?? governanceEmissionError.Message,
 20472            metadata: Metadata,
 20473            claimOwner: null,
 20474            claimToken: null,
 20475            claimedUtc: null,
 20476            claimExpiresUtc: null,
 20477            ClaimAttemptCount);
 478    }
 479
 480    private GovernanceOutboxEntry Copy(
 481        GovernanceEmissionStatus status,
 482        DateTimeOffset? updatedUtc,
 483        int retryCount,
 484        DateTimeOffset? nextRetryUtc,
 485        GovernanceEmissionError? lastError,
 486        string? providerName,
 487        string? providerRecordId,
 488        string? deadLetterReason,
 489        IReadOnlyDictionary<string, string> metadata,
 490        string? claimOwner,
 491        string? claimToken,
 492        DateTimeOffset? claimedUtc,
 493        DateTimeOffset? claimExpiresUtc,
 494        int claimAttemptCount)
 495    {
 204496        return new GovernanceOutboxEntry(
 204497            OutboxEntryId,
 204498            Envelope,
 204499            status,
 204500            CreatedUtc,
 204501            updatedUtc ?? DateTimeOffset.UtcNow,
 204502            retryCount,
 204503            MaxRetryCount,
 204504            nextRetryUtc,
 204505            lastError,
 204506            providerName,
 204507            providerRecordId,
 204508            deadLetterReason,
 204509            metadata,
 204510            claimOwner,
 204511            claimToken,
 204512            claimedUtc,
 204513            claimExpiresUtc,
 204514            claimAttemptCount);
 515    }
 516
 517    private static string NormalizeIdentifier(string? identifier)
 518    {
 347519        return string.IsNullOrWhiteSpace(identifier)
 347520            ? Guid.NewGuid().ToString("N")
 347521            : identifier.Trim();
 522    }
 523
 524    private static string? NormalizeOptional(string? value)
 525    {
 5515526        return string.IsNullOrWhiteSpace(value)
 5515527            ? null
 5515528            : value.Trim();
 529    }
 530
 531    private static IReadOnlyDictionary<string, string> MergeMetadata(
 532        IReadOnlyDictionary<string, string> originalMetadata,
 533        IReadOnlyDictionary<string, string> resultMetadata)
 534    {
 46535        if (resultMetadata.Count == 0)
 536        {
 39537            return originalMetadata;
 538        }
 539
 7540        if (originalMetadata.Count == 0)
 541        {
 5542            return resultMetadata;
 543        }
 544
 2545        Dictionary<string, string> mergedMetadata = new(originalMetadata.Count + resultMetadata.Count, StringComparer.Or
 546
 10547        foreach (KeyValuePair<string, string> item in originalMetadata)
 548        {
 3549            mergedMetadata[item.Key] = item.Value;
 550        }
 551
 10552        foreach (KeyValuePair<string, string> item in resultMetadata)
 553        {
 3554            mergedMetadata[item.Key] = item.Value;
 555        }
 556
 2557        return new ReadOnlyDictionary<string, string>(mergedMetadata);
 558    }
 559
 560    private static IReadOnlyDictionary<string, string> NormalizeMetadata(
 561        IReadOnlyDictionary<string, string>? metadata)
 562    {
 910563        if (metadata is null || metadata.Count == 0)
 564        {
 844565            return EmptyMetadata;
 566        }
 567
 66568        Dictionary<string, string> normalizedMetadata = new(metadata.Count, StringComparer.Ordinal);
 569
 290570        foreach (KeyValuePair<string, string> item in metadata)
 571        {
 79572            if (string.IsNullOrWhiteSpace(item.Key))
 573            {
 574                continue;
 575            }
 576
 76577            normalizedMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 578        }
 579
 66580        return normalizedMetadata.Count == 0
 66581            ? EmptyMetadata
 66582            : new ReadOnlyDictionary<string, string>(normalizedMetadata);
 583    }
 584}

Methods/Properties

.cctor()
.ctor(System.String,AsiBackbone.Core.Emissions.GovernanceEmissionEnvelope,AsiBackbone.Core.Emissions.GovernanceEmissionStatus,System.DateTimeOffset,System.DateTimeOffset,System.Int32,System.Int32,System.Nullable`1<System.DateTimeOffset>,AsiBackbone.Core.Emissions.GovernanceEmissionError,System.String,System.String,System.String,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>,System.String,System.String,System.Nullable`1<System.DateTimeOffset>,System.Nullable`1<System.DateTimeOffset>,System.Int32)
get_IsDelivered()
get_IsDeadLettered()
get_HasMetadata()
get_HasClaim()
Create(AsiBackbone.Core.Emissions.GovernanceEmissionEnvelope,System.String,System.Nullable`1<System.DateTimeOffset>,System.Int32,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
Restore(AsiBackbone.Core.Emissions.GovernanceEmissionEnvelope,AsiBackbone.Core.Emissions.GovernanceEmissionStatus,System.String,System.DateTimeOffset,System.DateTimeOffset,System.Int32,System.Int32,System.Nullable`1<System.DateTimeOffset>,AsiBackbone.Core.Emissions.GovernanceEmissionError,System.String,System.String,System.String,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>,System.String,System.String,System.Nullable`1<System.DateTimeOffset>,System.Nullable`1<System.DateTimeOffset>,System.Int32)
IsRetryReady(System.DateTimeOffset)
HasActiveClaim(System.DateTimeOffset)
CanBeClaimed(System.DateTimeOffset)
IsClaimedBy(AsiBackbone.Core.Outbox.GovernanceOutboxClaim)
MarkClaimed(System.String,System.String,System.Nullable`1<System.DateTimeOffset>,System.Nullable`1<System.TimeSpan>)
ReleaseClaim(System.Nullable`1<System.DateTimeOffset>)
MarkDelivered(AsiBackbone.Core.Emissions.GovernanceEmissionResult,System.Nullable`1<System.DateTimeOffset>)
MarkFailed(AsiBackbone.Core.Emissions.GovernanceEmissionError,System.Nullable`1<System.DateTimeOffset>,System.Nullable`1<System.DateTimeOffset>)
MarkDeferred(AsiBackbone.Core.Emissions.GovernanceEmissionError,System.Nullable`1<System.DateTimeOffset>,System.Nullable`1<System.DateTimeOffset>)
MarkDeadLettered(AsiBackbone.Core.Emissions.GovernanceEmissionError,System.String,System.Nullable`1<System.DateTimeOffset>)
Copy(AsiBackbone.Core.Emissions.GovernanceEmissionStatus,System.Nullable`1<System.DateTimeOffset>,System.Int32,System.Nullable`1<System.DateTimeOffset>,AsiBackbone.Core.Emissions.GovernanceEmissionError,System.String,System.String,System.String,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>,System.String,System.String,System.Nullable`1<System.DateTimeOffset>,System.Nullable`1<System.DateTimeOffset>,System.Int32)
NormalizeIdentifier(System.String)
NormalizeOptional(System.String)
MergeMetadata(System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>,System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)
NormalizeMetadata(System.Collections.Generic.IReadOnlyDictionary`2<System.String,System.String>)