< Summary

Information
Class: AsiBackbone.Core.Acknowledgments.AcknowledgmentRequest
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Acknowledgments/AcknowledgmentRequest.cs
Line coverage
100%
Covered lines: 104
Uncovered lines: 0
Coverable lines: 104
Total lines: 303
Line coverage: 100%
Branch coverage
100%
Covered branches: 22
Total branches: 22
Branch coverage: 100%
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%11100%
get_HasMetadata()100%11100%
Create(...)100%11100%
FromDecision(...)100%44100%
NormalizeIdentifier(...)100%22100%
NormalizeOptional(...)100%22100%
NormalizeMetadata(...)100%1414100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Acknowledgments/AcknowledgmentRequest.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2using AsiBackbone.Core.Actors;
 3using AsiBackbone.Core.Decisions;
 4using AsiBackbone.Core.Serialization;
 5
 6namespace AsiBackbone.Core.Acknowledgments;
 7
 8/// <summary>
 9/// Represents a framework-neutral liability or responsibility handshake request before consequential execution.
 10/// </summary>
 11public sealed class AcknowledgmentRequest
 12{
 213    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 214        new ReadOnlyDictionary<string, string>(
 215            new Dictionary<string, string>(StringComparer.Ordinal));
 16
 8217    private AcknowledgmentRequest(
 8218        string handshakeId,
 8219        string? schemaVersion,
 8220        string actorId,
 8221        GovernanceActorType actorType,
 8222        string? actorDisplayName,
 8223        string operationName,
 8224        string reasonCode,
 8225        string message,
 8226        string requiredAcknowledgmentCode,
 8227        string requiredAcknowledgmentText,
 8228        AcknowledgmentRiskLevel riskLevel,
 8229        string? riskCategory,
 8230        string? correlationId,
 8231        string? traceId,
 8232        string? policyVersion,
 8233        string? policyHash,
 8234        IReadOnlyDictionary<string, string> metadata)
 35    {
 8236        ArgumentException.ThrowIfNullOrWhiteSpace(handshakeId);
 8237        ArgumentException.ThrowIfNullOrWhiteSpace(actorId);
 8238        ArgumentException.ThrowIfNullOrWhiteSpace(operationName);
 8039        ArgumentException.ThrowIfNullOrWhiteSpace(reasonCode);
 7840        ArgumentException.ThrowIfNullOrWhiteSpace(message);
 7841        ArgumentException.ThrowIfNullOrWhiteSpace(requiredAcknowledgmentCode);
 7642        ArgumentException.ThrowIfNullOrWhiteSpace(requiredAcknowledgmentText);
 43
 7644        HandshakeId = handshakeId.Trim();
 7645        SchemaVersion = GovernanceSchemaVersions.Normalize(schemaVersion);
 7646        ActorId = actorId.Trim();
 7647        ActorType = actorType;
 7648        ActorDisplayName = NormalizeOptional(actorDisplayName);
 7649        OperationName = operationName.Trim();
 7650        ReasonCode = reasonCode.Trim();
 7651        Message = message.Trim();
 7652        RequiredAcknowledgmentCode = requiredAcknowledgmentCode.Trim();
 7653        RequiredAcknowledgmentText = requiredAcknowledgmentText.Trim();
 7654        RiskLevel = riskLevel;
 7655        RiskCategory = NormalizeOptional(riskCategory);
 7656        CorrelationId = NormalizeOptional(correlationId);
 7657        TraceId = NormalizeOptional(traceId);
 7658        PolicyVersion = NormalizeOptional(policyVersion);
 7659        PolicyHash = NormalizeOptional(policyHash);
 7660        Metadata = metadata;
 7661    }
 62
 63    /// <summary>
 64    /// Gets the stable handshake identifier.
 65    /// </summary>
 66    public string HandshakeId { get; }
 67
 68    /// <summary>
 69    /// Gets the schema version for the serialized handshake request shape.
 70    /// </summary>
 71    public string SchemaVersion { get; }
 72
 73    /// <summary>
 74    /// Gets the stable actor identifier associated with the handshake.
 75    /// </summary>
 76    public string ActorId { get; }
 77
 78    /// <summary>
 79    /// Gets the actor type associated with the handshake.
 80    /// </summary>
 81    public GovernanceActorType ActorType { get; }
 82
 83    /// <summary>
 84    /// Gets the optional display name or label associated with the actor.
 85    /// </summary>
 86    public string? ActorDisplayName { get; }
 87
 88    /// <summary>
 89    /// Gets the operation name requiring acknowledgment.
 90    /// </summary>
 91    public string OperationName { get; }
 92
 93    /// <summary>
 94    /// Gets the machine-readable reason code explaining why the handshake is required.
 95    /// </summary>
 96    public string ReasonCode { get; }
 97
 98    /// <summary>
 99    /// Gets the human-readable message explaining why the handshake is required.
 100    /// </summary>
 101    public string Message { get; }
 102
 103    /// <summary>
 104    /// Gets the required acknowledgment code the host may display or require before execution.
 105    /// </summary>
 106    public string RequiredAcknowledgmentCode { get; }
 107
 108    /// <summary>
 109    /// Gets the required acknowledgment text the host may display before execution.
 110    /// </summary>
 111    public string RequiredAcknowledgmentText { get; }
 112
 113    /// <summary>
 114    /// Gets the risk level associated with the handshake.
 115    /// </summary>
 116    public AcknowledgmentRiskLevel RiskLevel { get; }
 117
 118    /// <summary>
 119    /// Gets the optional host-defined risk category associated with the handshake.
 120    /// </summary>
 121    public string? RiskCategory { get; }
 122
 123    /// <summary>
 124    /// Gets the correlation identifier associated with the handshake, when supplied by the host.
 125    /// </summary>
 126    public string? CorrelationId { get; }
 127
 128    /// <summary>
 129    /// Gets the trace identifier associated with the handshake, when supplied by the host.
 130    /// </summary>
 131    public string? TraceId { get; }
 132
 133    /// <summary>
 134    /// Gets the policy version associated with the handshake, when supplied by the host.
 135    /// </summary>
 136    public string? PolicyVersion { get; }
 137
 138    /// <summary>
 139    /// Gets the policy hash associated with the handshake, when supplied by the host.
 140    /// </summary>
 141    public string? PolicyHash { get; }
 142
 143    /// <summary>
 144    /// Gets additional framework-neutral handshake metadata supplied by the host.
 145    /// </summary>
 146    public IReadOnlyDictionary<string, string> Metadata { get; }
 147
 148    /// <summary>
 149    /// Gets a value indicating whether this handshake contains metadata.
 150    /// </summary>
 10151    public bool HasMetadata => Metadata.Count > 0;
 152
 153    /// <summary>
 154    /// Creates a liability or responsibility handshake request.
 155    /// </summary>
 156    /// <param name="actor">The actor associated with the handshake.</param>
 157    /// <param name="operationName">The operation name requiring acknowledgment.</param>
 158    /// <param name="reasonCode">The machine-readable reason code.</param>
 159    /// <param name="message">The human-readable reason message.</param>
 160    /// <param name="requiredAcknowledgmentCode">The required acknowledgment code.</param>
 161    /// <param name="requiredAcknowledgmentText">The required acknowledgment text.</param>
 162    /// <param name="riskLevel">The risk level associated with the handshake.</param>
 163    /// <param name="riskCategory">Optional host-defined risk category.</param>
 164    /// <param name="handshakeId">Optional handshake identifier. When omitted, a new identifier is generated.</param>
 165    /// <param name="correlationId">Optional correlation identifier.</param>
 166    /// <param name="traceId">Optional trace identifier.</param>
 167    /// <param name="policyVersion">Optional policy version.</param>
 168    /// <param name="policyHash">Optional policy hash.</param>
 169    /// <param name="metadata">Optional host-provided metadata.</param>
 170    /// <param name="schemaVersion">Optional schema version for serialized or persisted handshake records.</param>
 171    /// <returns>A acknowledgment request.</returns>
 172    public static AcknowledgmentRequest Create(
 173        IGovernanceActorContext actor,
 174        string operationName,
 175        string reasonCode,
 176        string message,
 177        string requiredAcknowledgmentCode,
 178        string requiredAcknowledgmentText,
 179        AcknowledgmentRiskLevel riskLevel = AcknowledgmentRiskLevel.Unspecified,
 180        string? riskCategory = null,
 181        string? handshakeId = null,
 182        string? correlationId = null,
 183        string? traceId = null,
 184        string? policyVersion = null,
 185        string? policyHash = null,
 186        IReadOnlyDictionary<string, string>? metadata = null,
 187        string? schemaVersion = null)
 188    {
 83189        ArgumentNullException.ThrowIfNull(actor);
 190
 82191        return new AcknowledgmentRequest(
 82192            NormalizeIdentifier(handshakeId),
 82193            schemaVersion,
 82194            actor.ActorId,
 82195            actor.ActorType,
 82196            actor.DisplayName,
 82197            operationName,
 82198            reasonCode,
 82199            message,
 82200            requiredAcknowledgmentCode,
 82201            requiredAcknowledgmentText,
 82202            riskLevel,
 82203            riskCategory,
 82204            correlationId,
 82205            traceId,
 82206            policyVersion,
 82207            policyHash,
 82208            NormalizeMetadata(metadata));
 209    }
 210
 211    /// <summary>
 212    /// Creates a liability or responsibility handshake request from a governance decision.
 213    /// </summary>
 214    /// <param name="actor">The actor associated with the handshake.</param>
 215    /// <param name="operationName">The operation name requiring acknowledgment.</param>
 216    /// <param name="decision">The governance decision requiring acknowledgment.</param>
 217    /// <param name="requiredAcknowledgmentCode">The required acknowledgment code.</param>
 218    /// <param name="requiredAcknowledgmentText">The required acknowledgment text.</param>
 219    /// <param name="riskLevel">The risk level associated with the handshake.</param>
 220    /// <param name="riskCategory">Optional host-defined risk category.</param>
 221    /// <param name="handshakeId">Optional handshake identifier. When omitted, a new identifier is generated.</param>
 222    /// <param name="metadata">Optional host-provided metadata.</param>
 223    /// <param name="schemaVersion">Optional schema version for serialized or persisted handshake records.</param>
 224    /// <returns>A acknowledgment request.</returns>
 225    public static AcknowledgmentRequest FromDecision(
 226        IGovernanceActorContext actor,
 227        string operationName,
 228        GovernanceDecision decision,
 229        string requiredAcknowledgmentCode,
 230        string requiredAcknowledgmentText,
 231        AcknowledgmentRiskLevel riskLevel = AcknowledgmentRiskLevel.Unspecified,
 232        string? riskCategory = null,
 233        string? handshakeId = null,
 234        IReadOnlyDictionary<string, string>? metadata = null,
 235        string? schemaVersion = null)
 236    {
 37237        ArgumentNullException.ThrowIfNull(decision);
 238
 37239        string reasonCode = decision.ReasonCodes.Count > 0
 37240            ? decision.ReasonCodes[0]
 37241            : "handshake.required";
 242
 37243        string message = decision.Reasons.Count > 0
 37244            ? decision.Reasons[0].Message
 37245            : "Acknowledgment is required before proceeding.";
 246
 37247        return Create(
 37248            actor,
 37249            operationName,
 37250            reasonCode,
 37251            message,
 37252            requiredAcknowledgmentCode,
 37253            requiredAcknowledgmentText,
 37254            riskLevel,
 37255            riskCategory,
 37256            handshakeId,
 37257            decision.CorrelationId,
 37258            decision.TraceId,
 37259            decision.PolicyVersion,
 37260            decision.PolicyHash,
 37261            metadata,
 37262            schemaVersion);
 263    }
 264
 265    private static string NormalizeIdentifier(string? identifier)
 266    {
 82267        return string.IsNullOrWhiteSpace(identifier)
 82268            ? Guid.NewGuid().ToString("N")
 82269            : identifier.Trim();
 270    }
 271
 272    private static string? NormalizeOptional(string? value)
 273    {
 456274        return string.IsNullOrWhiteSpace(value)
 456275            ? null
 456276            : value.Trim();
 277    }
 278
 279    private static IReadOnlyDictionary<string, string> NormalizeMetadata(
 280        IReadOnlyDictionary<string, string>? metadata)
 281    {
 82282        if (metadata is null || metadata.Count == 0)
 283        {
 74284            return EmptyMetadata;
 285        }
 286
 8287        Dictionary<string, string> normalizedMetadata = new(StringComparer.Ordinal);
 288
 50289        foreach (KeyValuePair<string, string> item in metadata)
 290        {
 17291            if (string.IsNullOrWhiteSpace(item.Key))
 292            {
 293                continue;
 294            }
 295
 13296            normalizedMetadata[item.Key.Trim()] = item.Value?.Trim() ?? string.Empty;
 297        }
 298
 8299        return normalizedMetadata.Count == 0
 8300            ? EmptyMetadata
 8301            : new ReadOnlyDictionary<string, string>(normalizedMetadata);
 302    }
 303}