< Summary

Information
Class: AsiBackbone.Core.Decisions.GovernanceDecision
Assembly: AsiBackbone.Core
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Decisions/GovernanceDecision.cs
Line coverage
100%
Covered lines: 144
Uncovered lines: 0
Coverable lines: 144
Total lines: 490
Line coverage: 100%
Branch coverage
100%
Covered branches: 36
Total branches: 36
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_Outcome()100%11100%
get_Reasons()100%11100%
get_ReasonCodes()100%11100%
get_CorrelationId()100%11100%
get_TraceId()100%11100%
get_PolicyVersion()100%11100%
get_PolicyHash()100%11100%
get_CanProceed()100%22100%
get_IsAllowed()100%11100%
get_IsWarning()100%11100%
get_IsDenied()100%11100%
get_IsDeferred()100%11100%
get_RequiresAcknowledgment()100%11100%
get_EscalationRecommended()100%11100%
get_HasReasons()100%11100%
Allow(...)100%11100%
Deny(...)100%11100%
Deny(...)100%11100%
Deny(...)100%11100%
Warning(...)100%11100%
Warning(...)100%11100%
Warning(...)100%11100%
Defer(...)100%11100%
RequireAcknowledgment(...)100%11100%
Escalate(...)100%11100%
NormalizeOptional(...)100%22100%
NormalizeTelemetryIdentifier(...)100%44100%
NormalizeReasons(...)100%2424100%
CreateFallbackReason(...)100%11100%
CreateReasonCodes(...)100%44100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.Core/Decisions/GovernanceDecision.cs

#LineLine coverage
 1using System.Collections.ObjectModel;
 2using AsiBackbone.Core.Results;
 3
 4namespace AsiBackbone.Core.Decisions;
 5
 6/// <summary>
 7/// Represents a framework-neutral governance decision produced by an AsiBackbone evaluation flow.
 8/// </summary>
 9public sealed class GovernanceDecision
 10{
 11    private const string DefaultDeniedCode = "decision.denied";
 12    private const string DefaultDeniedMessage = "Decision denied the operation.";
 13    private const string DefaultWarningCode = "decision.warning";
 14    private const string DefaultWarningMessage = "Decision produced a warning.";
 15
 16    /// <summary>
 17    /// Defines the maximum retained length for normalized correlation identifiers.
 18    /// </summary>
 19    /// <remarks>
 20    /// Correlation identifiers are trimmed before enforcement. Values longer than this limit are truncated to keep tele
 21    /// </remarks>
 22    public const int MaxCorrelationIdLength = 256;
 23
 24    /// <summary>
 25    /// Defines the maximum retained length for normalized trace identifiers.
 26    /// </summary>
 27    /// <remarks>
 28    /// Trace identifiers are trimmed before enforcement. Values longer than this limit are truncated to keep telemetry-
 29    /// </remarks>
 30    public const int MaxTraceIdLength = 256;
 31
 432    private static readonly ReadOnlyCollection<OperationReason> EmptyReasons =
 433        Array.AsReadOnly(Array.Empty<OperationReason>());
 34
 435    private static readonly ReadOnlyCollection<string> EmptyReasonCodes =
 436        Array.AsReadOnly(Array.Empty<string>());
 37
 23238    private GovernanceDecision(
 23239        GovernanceDecisionOutcome outcome,
 23240        IReadOnlyList<OperationReason> reasons,
 23241        string? correlationId,
 23242        string? traceId,
 23243        string? policyVersion,
 23244        string? policyHash)
 45    {
 23246        Outcome = outcome;
 23247        Reasons = reasons;
 23248        ReasonCodes = CreateReasonCodes(reasons);
 23249        CorrelationId = NormalizeTelemetryIdentifier(correlationId, MaxCorrelationIdLength);
 23250        TraceId = NormalizeTelemetryIdentifier(traceId, MaxTraceIdLength);
 23251        PolicyVersion = NormalizeOptional(policyVersion);
 23252        PolicyHash = NormalizeOptional(policyHash);
 23253    }
 54
 55    /// <summary>
 56    /// Gets the selected governance decision outcome.
 57    /// </summary>
 32358    public GovernanceDecisionOutcome Outcome { get; }
 59
 60    /// <summary>
 61    /// Gets reasons associated with the governance decision.
 62    /// </summary>
 16463    public IReadOnlyList<OperationReason> Reasons { get; }
 64
 65    /// <summary>
 66    /// Gets machine-readable reason codes associated with the governance decision.
 67    /// </summary>
 23068    public IReadOnlyList<string> ReasonCodes { get; }
 69
 70    /// <summary>
 71    /// Gets the correlation identifier associated with the decision, when supplied by the host.
 72    /// </summary>
 12773    public string? CorrelationId { get; }
 74
 75    /// <summary>
 76    /// Gets the trace identifier associated with the decision, when supplied by the host.
 77    /// </summary>
 10078    public string? TraceId { get; }
 79
 80    /// <summary>
 81    /// Gets the policy version associated with the decision, when supplied by the host.
 82    /// </summary>
 10683    public string? PolicyVersion { get; }
 84
 85    /// <summary>
 86    /// Gets the policy hash associated with the decision, when supplied by the host.
 87    /// </summary>
 10688    public string? PolicyHash { get; }
 89
 90    /// <summary>
 91    /// Gets a value indicating whether the decision allows immediate execution.
 92    /// </summary>
 8693    public bool CanProceed => Outcome is GovernanceDecisionOutcome.Allowed or GovernanceDecisionOutcome.Warning;
 94
 95    /// <summary>
 96    /// Gets a value indicating whether the decision allows the operation.
 97    /// </summary>
 1498    public bool IsAllowed => Outcome is GovernanceDecisionOutcome.Allowed;
 99
 100    /// <summary>
 101    /// Gets a value indicating whether the decision allows the operation with warnings.
 102    /// </summary>
 21103    public bool IsWarning => Outcome is GovernanceDecisionOutcome.Warning;
 104
 105    /// <summary>
 106    /// Gets a value indicating whether the decision denies the operation.
 107    /// </summary>
 41108    public bool IsDenied => Outcome is GovernanceDecisionOutcome.Denied;
 109
 110    /// <summary>
 111    /// Gets a value indicating whether the decision defers the operation.
 112    /// </summary>
 14113    public bool IsDeferred => Outcome is GovernanceDecisionOutcome.Deferred;
 114
 115    /// <summary>
 116    /// Gets a value indicating whether the decision requires acknowledgment before execution.
 117    /// </summary>
 56118    public bool RequiresAcknowledgment => Outcome is GovernanceDecisionOutcome.AcknowledgmentRequired;
 119
 120    /// <summary>
 121    /// Gets a value indicating whether the decision recommends escalation.
 122    /// </summary>
 11123    public bool EscalationRecommended => Outcome is GovernanceDecisionOutcome.EscalationRecommended;
 124
 125    /// <summary>
 126    /// Gets a value indicating whether the decision includes reason data.
 127    /// </summary>
 12128    public bool HasReasons => Reasons.Count > 0;
 129
 130    /// <summary>
 131    /// Creates an allowed governance decision.
 132    /// </summary>
 133    /// <param name="correlationId">Optional correlation identifier.</param>
 134    /// <param name="traceId">Optional trace identifier.</param>
 135    /// <param name="policyVersion">Optional policy version.</param>
 136    /// <param name="policyHash">Optional policy hash.</param>
 137    /// <returns>An allowed governance decision.</returns>
 138    public static GovernanceDecision Allow(
 139        string? correlationId = null,
 140        string? traceId = null,
 141        string? policyVersion = null,
 142        string? policyHash = null)
 143    {
 64144        return new GovernanceDecision(
 64145            GovernanceDecisionOutcome.Allowed,
 64146            EmptyReasons,
 64147            correlationId,
 64148            traceId,
 64149            policyVersion,
 64150            policyHash);
 151    }
 152
 153    /// <summary>
 154    /// Creates a denied governance decision.
 155    /// </summary>
 156    /// <param name="code">The machine-readable reason code.</param>
 157    /// <param name="message">The human-readable reason message.</param>
 158    /// <param name="correlationId">Optional correlation identifier.</param>
 159    /// <param name="traceId">Optional trace identifier.</param>
 160    /// <param name="policyVersion">Optional policy version.</param>
 161    /// <param name="policyHash">Optional policy hash.</param>
 162    /// <returns>A denied governance decision.</returns>
 163    public static GovernanceDecision Deny(
 164        string code,
 165        string message,
 166        string? correlationId = null,
 167        string? traceId = null,
 168        string? policyVersion = null,
 169        string? policyHash = null)
 170    {
 29171        return Deny(
 29172            OperationReason.Create(code, message),
 29173            correlationId,
 29174            traceId,
 29175            policyVersion,
 29176            policyHash);
 177    }
 178
 179    /// <summary>
 180    /// Creates a denied governance decision.
 181    /// </summary>
 182    /// <param name="reason">The reason associated with the denied decision.</param>
 183    /// <param name="correlationId">Optional correlation identifier.</param>
 184    /// <param name="traceId">Optional trace identifier.</param>
 185    /// <param name="policyVersion">Optional policy version.</param>
 186    /// <param name="policyHash">Optional policy hash.</param>
 187    /// <returns>A denied governance decision.</returns>
 188    public static GovernanceDecision Deny(
 189        OperationReason reason,
 190        string? correlationId = null,
 191        string? traceId = null,
 192        string? policyVersion = null,
 193        string? policyHash = null)
 194    {
 32195        ArgumentNullException.ThrowIfNull(reason);
 196
 31197        return new GovernanceDecision(
 31198            GovernanceDecisionOutcome.Denied,
 31199            Array.AsReadOnly([reason]),
 31200            correlationId,
 31201            traceId,
 31202            policyVersion,
 31203            policyHash);
 204    }
 205
 206    /// <summary>
 207    /// Creates a denied governance decision.
 208    /// </summary>
 209    /// <param name="reasons">The reasons associated with the denied decision.</param>
 210    /// <param name="correlationId">Optional correlation identifier.</param>
 211    /// <param name="traceId">Optional trace identifier.</param>
 212    /// <param name="policyVersion">Optional policy version.</param>
 213    /// <param name="policyHash">Optional policy hash.</param>
 214    /// <returns>A denied governance decision.</returns>
 215    public static GovernanceDecision Deny(
 216        IEnumerable<OperationReason> reasons,
 217        string? correlationId = null,
 218        string? traceId = null,
 219        string? policyVersion = null,
 220        string? policyHash = null)
 221    {
 23222        return new GovernanceDecision(
 23223            GovernanceDecisionOutcome.Denied,
 23224            NormalizeReasons(reasons, DefaultDeniedCode, DefaultDeniedMessage),
 23225            correlationId,
 23226            traceId,
 23227            policyVersion,
 23228            policyHash);
 229    }
 230
 231    /// <summary>
 232    /// Creates a warning governance decision.
 233    /// </summary>
 234    /// <param name="code">The machine-readable reason code.</param>
 235    /// <param name="message">The human-readable reason message.</param>
 236    /// <param name="correlationId">Optional correlation identifier.</param>
 237    /// <param name="traceId">Optional trace identifier.</param>
 238    /// <param name="policyVersion">Optional policy version.</param>
 239    /// <param name="policyHash">Optional policy hash.</param>
 240    /// <returns>A warning governance decision.</returns>
 241    public static GovernanceDecision Warning(
 242        string code,
 243        string message,
 244        string? correlationId = null,
 245        string? traceId = null,
 246        string? policyVersion = null,
 247        string? policyHash = null)
 248    {
 5249        return Warning(
 5250            OperationReason.Create(code, message),
 5251            correlationId,
 5252            traceId,
 5253            policyVersion,
 5254            policyHash);
 255    }
 256
 257    /// <summary>
 258    /// Creates a warning governance decision.
 259    /// </summary>
 260    /// <param name="reason">The reason associated with the warning decision.</param>
 261    /// <param name="correlationId">Optional correlation identifier.</param>
 262    /// <param name="traceId">Optional trace identifier.</param>
 263    /// <param name="policyVersion">Optional policy version.</param>
 264    /// <param name="policyHash">Optional policy hash.</param>
 265    /// <returns>A warning governance decision.</returns>
 266    public static GovernanceDecision Warning(
 267        OperationReason reason,
 268        string? correlationId = null,
 269        string? traceId = null,
 270        string? policyVersion = null,
 271        string? policyHash = null)
 272    {
 23273        ArgumentNullException.ThrowIfNull(reason);
 274
 22275        return new GovernanceDecision(
 22276            GovernanceDecisionOutcome.Warning,
 22277            Array.AsReadOnly([reason]),
 22278            correlationId,
 22279            traceId,
 22280            policyVersion,
 22281            policyHash);
 282    }
 283
 284    /// <summary>
 285    /// Creates a warning governance decision.
 286    /// </summary>
 287    /// <param name="reasons">The reasons associated with the warning decision.</param>
 288    /// <param name="correlationId">Optional correlation identifier.</param>
 289    /// <param name="traceId">Optional trace identifier.</param>
 290    /// <param name="policyVersion">Optional policy version.</param>
 291    /// <param name="policyHash">Optional policy hash.</param>
 292    /// <returns>A warning governance decision.</returns>
 293    public static GovernanceDecision Warning(
 294        IEnumerable<OperationReason> reasons,
 295        string? correlationId = null,
 296        string? traceId = null,
 297        string? policyVersion = null,
 298        string? policyHash = null)
 299    {
 12300        return new GovernanceDecision(
 12301            GovernanceDecisionOutcome.Warning,
 12302            NormalizeReasons(reasons, DefaultWarningCode, DefaultWarningMessage),
 12303            correlationId,
 12304            traceId,
 12305            policyVersion,
 12306            policyHash);
 307    }
 308
 309    /// <summary>
 310    /// Creates a deferred governance decision.
 311    /// </summary>
 312    /// <param name="code">The machine-readable reason code.</param>
 313    /// <param name="message">The human-readable reason message.</param>
 314    /// <param name="correlationId">Optional correlation identifier.</param>
 315    /// <param name="traceId">Optional trace identifier.</param>
 316    /// <param name="policyVersion">Optional policy version.</param>
 317    /// <param name="policyHash">Optional policy hash.</param>
 318    /// <returns>A deferred governance decision.</returns>
 319    public static GovernanceDecision Defer(
 320        string code,
 321        string message,
 322        string? correlationId = null,
 323        string? traceId = null,
 324        string? policyVersion = null,
 325        string? policyHash = null)
 326    {
 12327        return new GovernanceDecision(
 12328            GovernanceDecisionOutcome.Deferred,
 12329            Array.AsReadOnly([OperationReason.Create(code, message)]),
 12330            correlationId,
 12331            traceId,
 12332            policyVersion,
 12333            policyHash);
 334    }
 335
 336    /// <summary>
 337    /// Creates an acknowledgment-required governance decision.
 338    /// </summary>
 339    /// <param name="code">The machine-readable reason code.</param>
 340    /// <param name="message">The human-readable reason message.</param>
 341    /// <param name="correlationId">Optional correlation identifier.</param>
 342    /// <param name="traceId">Optional trace identifier.</param>
 343    /// <param name="policyVersion">Optional policy version.</param>
 344    /// <param name="policyHash">Optional policy hash.</param>
 345    /// <returns>An acknowledgment-required governance decision.</returns>
 346    public static GovernanceDecision RequireAcknowledgment(
 347        string code,
 348        string message,
 349        string? correlationId = null,
 350        string? traceId = null,
 351        string? policyVersion = null,
 352        string? policyHash = null)
 353    {
 59354        return new GovernanceDecision(
 59355            GovernanceDecisionOutcome.AcknowledgmentRequired,
 59356            Array.AsReadOnly([OperationReason.Create(code, message)]),
 59357            correlationId,
 59358            traceId,
 59359            policyVersion,
 59360            policyHash);
 361    }
 362
 363    /// <summary>
 364    /// Creates an escalation-recommended governance decision.
 365    /// </summary>
 366    /// <param name="code">The machine-readable reason code.</param>
 367    /// <param name="message">The human-readable reason message.</param>
 368    /// <param name="correlationId">Optional correlation identifier.</param>
 369    /// <param name="traceId">Optional trace identifier.</param>
 370    /// <param name="policyVersion">Optional policy version.</param>
 371    /// <param name="policyHash">Optional policy hash.</param>
 372    /// <returns>An escalation-recommended governance decision.</returns>
 373    public static GovernanceDecision Escalate(
 374        string code,
 375        string message,
 376        string? correlationId = null,
 377        string? traceId = null,
 378        string? policyVersion = null,
 379        string? policyHash = null)
 380    {
 9381        return new GovernanceDecision(
 9382            GovernanceDecisionOutcome.EscalationRecommended,
 9383            Array.AsReadOnly([OperationReason.Create(code, message)]),
 9384            correlationId,
 9385            traceId,
 9386            policyVersion,
 9387            policyHash);
 388    }
 389
 390    private static string? NormalizeOptional(string? value)
 391    {
 928392        return string.IsNullOrWhiteSpace(value)
 928393            ? null
 928394            : value.Trim();
 395    }
 396
 397    private static string? NormalizeTelemetryIdentifier(string? value, int maxLength)
 398    {
 464399        string? normalized = NormalizeOptional(value);
 400
 464401        return normalized is null || normalized.Length <= maxLength
 464402            ? normalized
 464403            : normalized[..maxLength];
 404    }
 405
 406    private static ReadOnlyCollection<OperationReason> NormalizeReasons(
 407        IEnumerable<OperationReason>? reasons,
 408        string fallbackCode,
 409        string fallbackMessage)
 410    {
 35411        if (reasons is null)
 412        {
 2413            return CreateFallbackReason(fallbackCode, fallbackMessage);
 414        }
 415
 33416        if (reasons is ICollection<OperationReason> collection)
 417        {
 28418            if (collection.Count == 0)
 419            {
 2420                return CreateFallbackReason(fallbackCode, fallbackMessage);
 421            }
 422
 26423            var normalizedReasons = new OperationReason[collection.Count];
 26424            int normalizedCount = 0;
 425
 124426            foreach (OperationReason? reason in collection)
 427            {
 36428                if (reason is not null)
 429                {
 32430                    normalizedReasons[normalizedCount] = reason;
 32431                    normalizedCount++;
 432                }
 433            }
 434
 26435            if (normalizedCount == 0)
 436            {
 2437                return CreateFallbackReason(fallbackCode, fallbackMessage);
 438            }
 439
 24440            if (normalizedCount == normalizedReasons.Length)
 441            {
 22442                return Array.AsReadOnly(normalizedReasons);
 443            }
 444
 2445            var filteredReasons = new OperationReason[normalizedCount];
 2446            Array.Copy(normalizedReasons, filteredReasons, normalizedCount);
 447
 2448            return Array.AsReadOnly(filteredReasons);
 449        }
 450
 5451        List<OperationReason>? normalizedList = null;
 452
 26453        foreach (OperationReason? reason in reasons)
 454        {
 8455            if (reason is not null)
 456            {
 8457                normalizedList ??= [];
 8458                normalizedList.Add(reason);
 459            }
 460        }
 461
 5462        return normalizedList is null || normalizedList.Count == 0
 5463            ? CreateFallbackReason(fallbackCode, fallbackMessage)
 5464            : Array.AsReadOnly([.. normalizedList]);
 465    }
 466
 467    private static ReadOnlyCollection<OperationReason> CreateFallbackReason(
 468        string fallbackCode,
 469        string fallbackMessage)
 470    {
 7471        return Array.AsReadOnly([OperationReason.Create(fallbackCode, fallbackMessage)]);
 472    }
 473
 474    private static ReadOnlyCollection<string> CreateReasonCodes(IReadOnlyList<OperationReason> reasons)
 475    {
 232476        if (reasons.Count == 0)
 477        {
 64478            return EmptyReasonCodes;
 479        }
 480
 168481        string[] reasonCodes = new string[reasons.Count];
 482
 696483        for (int index = 0; index < reasons.Count; index++)
 484        {
 180485            reasonCodes[index] = reasons[index].Code;
 486        }
 487
 168488        return Array.AsReadOnly(reasonCodes);
 489    }
 490}

Methods/Properties

.cctor()
.ctor(AsiBackbone.Core.Decisions.GovernanceDecisionOutcome,System.Collections.Generic.IReadOnlyList`1<AsiBackbone.Core.Results.OperationReason>,System.String,System.String,System.String,System.String)
get_Outcome()
get_Reasons()
get_ReasonCodes()
get_CorrelationId()
get_TraceId()
get_PolicyVersion()
get_PolicyHash()
get_CanProceed()
get_IsAllowed()
get_IsWarning()
get_IsDenied()
get_IsDeferred()
get_RequiresAcknowledgment()
get_EscalationRecommended()
get_HasReasons()
Allow(System.String,System.String,System.String,System.String)
Deny(System.String,System.String,System.String,System.String,System.String,System.String)
Deny(AsiBackbone.Core.Results.OperationReason,System.String,System.String,System.String,System.String)
Deny(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>,System.String,System.String,System.String,System.String)
Warning(System.String,System.String,System.String,System.String,System.String,System.String)
Warning(AsiBackbone.Core.Results.OperationReason,System.String,System.String,System.String,System.String)
Warning(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>,System.String,System.String,System.String,System.String)
Defer(System.String,System.String,System.String,System.String,System.String,System.String)
RequireAcknowledgment(System.String,System.String,System.String,System.String,System.String,System.String)
Escalate(System.String,System.String,System.String,System.String,System.String,System.String)
NormalizeOptional(System.String)
NormalizeTelemetryIdentifier(System.String,System.Int32)
NormalizeReasons(System.Collections.Generic.IEnumerable`1<AsiBackbone.Core.Results.OperationReason>,System.String,System.String)
CreateFallbackReason(System.String,System.String)
CreateReasonCodes(System.Collections.Generic.IReadOnlyList`1<AsiBackbone.Core.Results.OperationReason>)