Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Globalization
Imports System.Reflection
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Composition

    ''' <summary>
    ''' Severity for deterministic Composition runtime stress verification. Errors block the
    ''' certification gate; warnings preserve commercial evidence without changing runtime paths.
    ''' </summary>
    Friend Enum MASCompositionRuntimeStressFindingSeverity
        Info = 0
        Warning = 1
        [Error] = 2
    End Enum

    ''' <summary>
    ''' Runtime stress surfaces covered by the Composition proof. These recipes are deliberately
    ''' non-visual and host-independent so they can run inside the existing certification system.
    ''' </summary>
    Friend Enum MASCompositionRuntimeStressFindingKind
        ScrollRecordRealization = 0
        ScrollInputStormBoundedLookup = 1
        ScrollOwnerCleanup = 2
        RetainedScrollScalabilityPolicy = 3
        RetainedScrollLayoutNodeBlock = 4
        RefreshDiagnosticsEvidence = 5
        LifecycleCleanupEvidence = 6
    End Enum

    ''' <summary>
    ''' Immutable finding emitted by the Composition runtime stress audit.
    ''' </summary>
    Friend NotInheritable Class MASCompositionRuntimeStressFinding
        Friend ReadOnly Property Severity As MASCompositionRuntimeStressFindingSeverity
        Friend ReadOnly Property Kind As MASCompositionRuntimeStressFindingKind
        Friend ReadOnly Property Code As String
        Friend ReadOnly Property Message As String

        Friend Sub New(severity As MASCompositionRuntimeStressFindingSeverity,
                       kind As MASCompositionRuntimeStressFindingKind,
                       code As String,
                       message As String)
            Me.Severity = severity
            Me.Kind = kind
            Me.Code = If(code, String.Empty).Trim()
            Me.Message = If(message, String.Empty).Trim()
        End Sub

        Public Overrides Function ToString() As String
            Return Severity.ToString() & " | " & Kind.ToString() & " | " & Code & " | " & Message
        End Function
    End Class

    ''' <summary>
    ''' Immutable report for deterministic Composition runtime stress verification.
    ''' </summary>
    Friend NotInheritable Class MASCompositionRuntimeStressReport
        Private ReadOnly _findings As ReadOnlyCollection(Of MASCompositionRuntimeStressFinding)

        Friend Sub New(probeCount As Integer,
                       stressRecordCount As Integer,
                       maxLookupProbeCount As Integer,
                       findings As IEnumerable(Of MASCompositionRuntimeStressFinding))
            Me.ProbeCount = Math.Max(0, probeCount)
            Me.StressRecordCount = Math.Max(0, stressRecordCount)
            Me.MaxLookupProbeCount = Math.Max(0, maxLookupProbeCount)

            Dim normalized As New List(Of MASCompositionRuntimeStressFinding)()
            If findings IsNot Nothing Then
                For Each finding As MASCompositionRuntimeStressFinding In findings
                    If finding IsNot Nothing Then normalized.Add(finding)
                Next
            End If

            _findings = New ReadOnlyCollection(Of MASCompositionRuntimeStressFinding)(normalized)
        End Sub

        Friend ReadOnly Property ProbeCount As Integer
        Friend ReadOnly Property StressRecordCount As Integer
        Friend ReadOnly Property MaxLookupProbeCount As Integer

        Friend ReadOnly Property Findings As ReadOnlyCollection(Of MASCompositionRuntimeStressFinding)
            Get
                Return _findings
            End Get
        End Property

        Friend ReadOnly Property ErrorCount As Integer
            Get
                Return CountBySeverity(MASCompositionRuntimeStressFindingSeverity.Error)
            End Get
        End Property

        Friend ReadOnly Property WarningCount As Integer
            Get
                Return CountBySeverity(MASCompositionRuntimeStressFindingSeverity.Warning)
            End Get
        End Property

        Friend ReadOnly Property InfoCount As Integer
            Get
                Return CountBySeverity(MASCompositionRuntimeStressFindingSeverity.Info)
            End Get
        End Property

        Friend ReadOnly Property IsVerified As Boolean
            Get
                Return ProbeCount > 0 AndAlso StressRecordCount >= MASCompositionRuntimeStressVerificationAudit.DefaultStressScrollRecordCount AndAlso ErrorCount = 0
            End Get
        End Property

        Friend ReadOnly Property Summary As String
            Get
                If IsVerified Then
                    Return ProbeCount.ToString(CultureInfo.InvariantCulture) &
                           " Composition runtime stress probe(s) passed for " &
                           StressRecordCount.ToString(CultureInfo.InvariantCulture) &
                           " scroll region(s), bounded lookup, owner cleanup, lifecycle evidence, refresh diagnostics evidence, retained-scroll scalability policy, and retained-scroll layout-node blocking."
                End If

                Return ErrorCount.ToString(CultureInfo.InvariantCulture) &
                       " blocking Composition runtime stress verification error(s) were found across " &
                       ProbeCount.ToString(CultureInfo.InvariantCulture) & " probe(s)."
            End Get
        End Property

        Friend Function CreateFindingDetails(maxItems As Integer) As IReadOnlyList(Of String)
            Dim details As New List(Of String)()
            Dim limit As Integer = Math.Max(0, maxItems)
            For Each finding As MASCompositionRuntimeStressFinding In _findings
                If details.Count >= limit Then Exit For
                details.Add(finding.ToString())
            Next
            Return New ReadOnlyCollection(Of String)(details)
        End Function

        Friend Function CreateSummaryDetails() As IReadOnlyList(Of String)
            Dim details As New List(Of String) From {
                "Probe count: " & ProbeCount.ToString(CultureInfo.InvariantCulture),
                "Stress scroll records: " & StressRecordCount.ToString(CultureInfo.InvariantCulture),
                "Max lookup probes observed: " & MaxLookupProbeCount.ToString(CultureInfo.InvariantCulture),
                "Errors: " & ErrorCount.ToString(CultureInfo.InvariantCulture),
                "Warnings: " & WarningCount.ToString(CultureInfo.InvariantCulture),
                "Runtime proof: Composition scroll input storms exercise MASCompositionScrollState with 1k retained scroll records, bounded spatial lookup, owner cleanup, retained-scroll scalability policy, retained-scroll layout-node blocking, lifecycle cleanup evidence, and refresh diagnostics evidence."
            }

            For Each finding As MASCompositionRuntimeStressFinding In _findings
                If finding.Severity <> MASCompositionRuntimeStressFindingSeverity.Info AndAlso details.Count < 16 Then details.Add(finding.ToString())
            Next

            Return New ReadOnlyCollection(Of String)(details)
        End Function

        Private Function CountBySeverity(severity As MASCompositionRuntimeStressFindingSeverity) As Integer
            Dim count As Integer = 0
            For Each finding As MASCompositionRuntimeStressFinding In _findings
                If finding.Severity = severity Then count += 1
            Next
            Return count
        End Function
    End Class

    ''' <summary>
    ''' Host-independent runtime stress verification for Composition hardening. It does not create a
    ''' parallel layout path: it drives the official MASCompositionScrollState, the official MAS Scroll
    ''' adapter factory, and the retained-scroll scalability policy used by MASVerticalScrollLayoutNode.
    ''' </summary>
    Friend NotInheritable Class MASCompositionRuntimeStressVerificationAudit
        Friend Const DefaultStressScrollRecordCount As Integer = 1000
        Private Const MaxExpectedLookupProbes As Integer = 16
        Private Const StressViewportWidth As Single = 240.0F
        Private Const StressViewportHeight As Single = 40.0F
        Private Const StressRowSpacing As Single = 128.0F
        Private Const StressContentHeight As Single = 480.0F
        Private Const StressOwnerKey As String = "MASComposition.RuntimeStress.Owner."

        Private Sub New()
        End Sub

        Friend Shared Function VerifyCurrent() As MASCompositionRuntimeStressReport
            Dim findings As New List(Of MASCompositionRuntimeStressFinding)()
            Dim probeCount As Integer = 0
            Dim maxLookupProbeCount As Integer = 0

            Try
                VerifyScrollInputStormBoundedLookup(findings, probeCount, maxLookupProbeCount)
                VerifyRetainedScrollScalabilityPolicy(findings, probeCount)
                VerifyRetainedScrollLayoutNodeBlocking(findings, probeCount)
                VerifyLifecycleCleanupEvidence(findings, probeCount)
                VerifyRefreshDiagnosticsEvidence(findings, probeCount)
            Catch masCaughtCompositionStressException As Exception
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.ScrollInputStormBoundedLookup,
                         "MASComposition.RuntimeStress.Exception",
                         "Composition runtime stress verification threw before completing: " & masCaughtCompositionStressException.GetType().Name & ": " & masCaughtCompositionStressException.Message)
            End Try

            If findings.Count = 0 Then
                AddInfo(findings,
                        MASCompositionRuntimeStressFindingKind.ScrollInputStormBoundedLookup,
                        "MASComposition.RuntimeStress.NoFindings",
                        "All Composition runtime stress verification probes completed without warning or error findings.")
            End If

            Return New MASCompositionRuntimeStressReport(probeCount, DefaultStressScrollRecordCount, maxLookupProbeCount, findings)
        End Function

        Private Shared Sub VerifyScrollInputStormBoundedLookup(findings As IList(Of MASCompositionRuntimeStressFinding),
                                                               ByRef probeCount As Integer,
                                                               ByRef maxLookupProbeCount As Integer)
            Dim invalidationCount As Integer = 0
            Dim state As New MASCompositionScrollState(Sub() invalidationCount += 1)
            Dim ctx As MASThemeContext = CreateStressThemeContext()
            Dim requests As MASLayoutScrollRequest() = BuildStressScrollRequests(DefaultStressScrollRecordCount)

            probeCount += 1
            state.ApplyRequests(requests, StressOwnerKey, ctx)
            Dim realized As Integer = state.RuntimeRecordCountForOwner(StressOwnerKey)
            If realized <> DefaultStressScrollRecordCount Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.ScrollRecordRealization,
                         "MASComposition.RuntimeStress.ScrollRecordCount",
                         "Expected " & DefaultStressScrollRecordCount.ToString(CultureInfo.InvariantCulture) &
                         " Composition scroll records, actual " & realized.ToString(CultureInfo.InvariantCulture) & ".")
            End If

            Dim targetIndex As Integer = DefaultStressScrollRecordCount \ 2
            Dim viewportPoint As New SKPoint(24.0F, CSng(targetIndex) * StressRowSpacing + 12.0F)
            Dim scrollbarPoint As New SKPoint(StressViewportWidth - 4.0F, CSng(targetIndex) * StressRowSpacing + 12.0F)

            probeCount += 1
            Dim viewportCandidates As Integer = state.RuntimeCandidateCountAt(StressOwnerKey, viewportPoint, False)
            If viewportCandidates <= 0 OrElse viewportCandidates > MaxExpectedLookupProbes Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.ScrollInputStormBoundedLookup,
                         "MASComposition.RuntimeStress.ViewportCandidates",
                         "Viewport hit-test candidates were not bounded. Candidates=" & viewportCandidates.ToString(CultureInfo.InvariantCulture) & ".")
            End If

            probeCount += 1
            state.TryWheelAt(StressOwnerKey, viewportPoint, -120)
            maxLookupProbeCount = Math.Max(maxLookupProbeCount, state.LastHitTestProbeCount)
            If state.LastHitTestProbeCount <= 0 OrElse state.LastHitTestProbeCount > MaxExpectedLookupProbes Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.ScrollInputStormBoundedLookup,
                         "MASComposition.RuntimeStress.WheelProbeCount",
                         "Wheel input lookup was not bounded. ProbeCount=" & state.LastHitTestProbeCount.ToString(CultureInfo.InvariantCulture) &
                         "; CandidateCount=" & state.LastHitTestCandidateCount.ToString(CultureInfo.InvariantCulture) & ".")
            End If

            probeCount += 1
            Dim scrollbarCandidates As Integer = state.RuntimeCandidateCountAt(StressOwnerKey, scrollbarPoint, True)
            If scrollbarCandidates <= 0 OrElse scrollbarCandidates > MaxExpectedLookupProbes Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.ScrollInputStormBoundedLookup,
                         "MASComposition.RuntimeStress.ScrollbarCandidates",
                         "Scrollbar hit-test candidates were not bounded. Candidates=" & scrollbarCandidates.ToString(CultureInfo.InvariantCulture) & ".")
            End If

            probeCount += 1
            state.TryPointerMoveAt(StressOwnerKey, scrollbarPoint)
            maxLookupProbeCount = Math.Max(maxLookupProbeCount, state.LastHitTestProbeCount)
            If state.LastHitTestProbeCount <= 0 OrElse state.LastHitTestProbeCount > MaxExpectedLookupProbes Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.ScrollInputStormBoundedLookup,
                         "MASComposition.RuntimeStress.PointerMoveProbeCount",
                         "Pointer-move lookup was not bounded. ProbeCount=" & state.LastHitTestProbeCount.ToString(CultureInfo.InvariantCulture) &
                         "; CandidateCount=" & state.LastHitTestCandidateCount.ToString(CultureInfo.InvariantCulture) & ".")
            End If

            probeCount += 1
            state.PointerLeave(StressOwnerKey)
            state.ClearOwner(StressOwnerKey)
            If state.RuntimeRecordCountForOwner(StressOwnerKey) <> 0 OrElse state.RuntimeRecordCount <> 0 Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.ScrollOwnerCleanup,
                         "MASComposition.RuntimeStress.ScrollOwnerCleanup",
                         "Composition scroll owner cleanup left records attached after the stress recipe. RemainingRecords=" & state.RuntimeRecordCount.ToString(CultureInfo.InvariantCulture) & ".")
            End If
        End Sub

        Private Shared Sub VerifyRetainedScrollScalabilityPolicy(findings As IList(Of MASCompositionRuntimeStressFinding),
                                                                 ByRef probeCount As Integer)
            probeCount += 1
            If Not MASCompositionScrollScalabilityPolicy.ShouldWarn(128, 64, 400.0F, 1600.0F) Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RetainedScrollScalabilityPolicy,
                         "MASComposition.RuntimeStress.ScrollWarnPolicy",
                         "Retained Composition scroll did not warn at the documented commercial warning threshold.")
            End If

            probeCount += 1
            If Not MASCompositionScrollScalabilityPolicy.ShouldBlock(DefaultStressScrollRecordCount, 512, 400.0F, 120000.0F) Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RetainedScrollScalabilityPolicy,
                         "MASComposition.RuntimeStress.ScrollBlockPolicy",
                         "Retained Composition scroll did not block a 1k/10k-style non-virtualized misuse before ControlsLayer mutation.")
            End If

            probeCount += 1
            Dim detail As String = MASCompositionScrollScalabilityPolicy.BuildBlockDetail(DefaultStressScrollRecordCount, 512, 400.0F, 120000.0F)
            If detail.IndexOf("Action=BlockedBeforeRetainedPlacementPublication", StringComparison.Ordinal) < 0 OrElse
               detail.IndexOf("ControlsLayerAction=BlockedBeforeControlsLayerMutation", StringComparison.Ordinal) < 0 OrElse
               detail.IndexOf("MASVirtualizedItemsSystem", StringComparison.Ordinal) < 0 Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RetainedScrollScalabilityPolicy,
                         "MASComposition.RuntimeStress.ScrollBlockDetail",
                         "Retained Composition scroll block diagnostics do not identify the fail-before-placement-publication action, fail-before-mutate action, and official virtualization owner route.")
            End If
        End Sub

        Private Shared Sub VerifyRetainedScrollLayoutNodeBlocking(findings As IList(Of MASCompositionRuntimeStressFinding),
                                                                           ByRef probeCount As Integer)
            probeCount += 1

            Dim diagnostics As New MASLayoutDiagnosticBag()
            Dim content As New RetainedScrollStressContentNode(DefaultStressScrollRecordCount, 24.0F, 20.0F)
            Dim node As New MASVerticalScrollLayoutNode(content, "MASComposition.RuntimeStress.RetainedScroll.Node")

            node.Measure(New MASLayoutMeasureContext(New SKSize(240.0F, 120.0F), MASSizeLayoutIntegrationContext.Empty, diagnostics))
            Dim result As MASLayoutArrangeResult = node.Arrange(New MASLayoutArrangeContext(
                boundsLogical:=New SKRect(0.0F, 0.0F, 240.0F, 120.0F),
                integrationContext:=MASSizeLayoutIntegrationContext.Empty,
                diagnostics:=diagnostics))

            If result Is Nothing Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RetainedScrollLayoutNodeBlock,
                         "MASComposition.RuntimeStress.ScrollNodeMissingResult",
                         "Retained Composition scroll node did not return a safe arrange result for blocked large content.")
                Return
            End If

            If Not diagnostics.HasErrors Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RetainedScrollLayoutNodeBlock,
                         "MASComposition.RuntimeStress.ScrollNodeNoBlockDiagnostic",
                         "Retained Composition scroll node did not emit a blocking diagnostic for 1k non-virtualized placements.")
            End If

            If result.Placements.Length <> 0 Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RetainedScrollLayoutNodeBlock,
                         "MASComposition.RuntimeStress.ScrollNodePublishedPlacements",
                         "Retained Composition scroll node published " & result.Placements.Length.ToString(CultureInfo.InvariantCulture) & " placements after the block policy fired. Blocked results must not publish retained placements downstream.")
            End If

            Dim sawBlockCode As Boolean = False
            For Each diagnostic As MASLayoutDiagnostic In diagnostics.ToArray()
                If diagnostic IsNot Nothing AndAlso String.Equals(diagnostic.Code, MASCompositionScrollScalabilityPolicy.NonVirtualizedScrollScalabilityBlockCode, StringComparison.Ordinal) Then
                    sawBlockCode = True
                    Exit For
                End If
            Next

            If Not sawBlockCode Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RetainedScrollLayoutNodeBlock,
                         "MASComposition.RuntimeStress.ScrollNodeBlockCodeMissing",
                         "Retained Composition scroll node did not emit the canonical non-virtualized scroll block diagnostic code.")
            End If
        End Sub

        Private Shared Sub VerifyLifecycleCleanupEvidence(findings As IList(Of MASCompositionRuntimeStressFinding),
                                                          ByRef probeCount As Integer)
            probeCount += 1
            Dim runtimeType As Type = GetType(MASCompositionHostRuntime)
            Dim clearMethod As MethodInfo = runtimeType.GetMethod("Clear", BindingFlags.Instance Or BindingFlags.NonPublic)
            Dim disposeMethod As MethodInfo = runtimeType.GetMethod("Dispose", BindingFlags.Instance Or BindingFlags.Public)

            If clearMethod Is Nothing OrElse disposeMethod Is Nothing Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.LifecycleCleanupEvidence,
                         "MASComposition.RuntimeStress.LifecycleMethods",
                         "Composition runtime lifecycle methods could not be reflected for certification evidence.")
            End If
        End Sub

        Private Shared Sub VerifyRefreshDiagnosticsEvidence(findings As IList(Of MASCompositionRuntimeStressFinding),
                                                            ByRef probeCount As Integer)
            probeCount += 1
            Dim controlsType As Type = GetType(Nexamas.UI.Application.MASApplicationWindowControls)
            Dim failureEvent As EventInfo = controlsType.GetEvent("LayoutRefreshFailed", BindingFlags.Instance Or BindingFlags.Public)
            Dim failureProperty As PropertyInfo = controlsType.GetProperty("HasLastLayoutRefreshFailure", BindingFlags.Instance Or BindingFlags.Public)
            Dim messageProperty As PropertyInfo = controlsType.GetProperty("LastLayoutRefreshFailureMessage", BindingFlags.Instance Or BindingFlags.Public)

            If failureEvent Is Nothing OrElse failureProperty Is Nothing OrElse messageProperty Is Nothing Then
                AddError(findings,
                         MASCompositionRuntimeStressFindingKind.RefreshDiagnosticsEvidence,
                         "MASComposition.RuntimeStress.RefreshDiagnostics",
                         "Developer-visible Application layout refresh diagnostics are not exposed on MASApplicationWindow.Controls.")
            End If
        End Sub

        Private Shared Function BuildStressScrollRequests(count As Integer) As MASLayoutScrollRequest()
            Dim safeCount As Integer = Math.Max(0, count)
            If safeCount = 0 Then Return New MASLayoutScrollRequest() {}

            Dim requests(safeCount - 1) As MASLayoutScrollRequest

            For i As Integer = 0 To safeCount - 1
                Dim top As Single = CSng(i) * StressRowSpacing
                requests(i) = New MASLayoutScrollRequest(
                    key:="Stress.Scroll." & i.ToString(CultureInfo.InvariantCulture),
                    viewportLogical:=New SKRect(0.0F, top, StressViewportWidth, top + StressViewportHeight),
                    contentHeightLogical:=StressContentHeight,
                    viewportHeightLogical:=StressViewportHeight)
            Next

            Return requests
        End Function

        Private Shared Function CreateStressThemeContext() As MASThemeContext
            Return New MASThemeContext(1.0F, New MASTypography(1.0F), ThemeManager.CurrentCore, 0)
        End Function

        Private NotInheritable Class RetainedScrollStressContentNode
            Implements IMASLayoutNode

            Private ReadOnly _count As Integer
            Private ReadOnly _rowPitch As Single
            Private ReadOnly _rowHeight As Single

            Friend Sub New(count As Integer,
                           rowPitch As Single,
                           rowHeight As Single)
                _count = Math.Max(0, count)
                _rowPitch = Math.Max(1.0F, rowPitch)
                _rowHeight = Math.Max(1.0F, Math.Min(_rowPitch, rowHeight))
            End Sub

            Public Function Measure(context As MASLayoutMeasureContext) As SKSize Implements IMASLayoutNode.Measure
                Dim width As Single = 240.0F
                If context IsNot Nothing AndAlso context.AvailableSize.Width > 1.0F AndAlso Not Single.IsInfinity(context.AvailableSize.Width) Then
                    width = context.AvailableSize.Width
                End If

                Return New SKSize(width, CSng(_count) * _rowPitch)
            End Function

            Public Function Arrange(context As MASLayoutArrangeContext) As MASLayoutArrangeResult Implements IMASLayoutNode.Arrange
                Dim result As New MASLayoutArrangeResult()
                If context Is Nothing Then Return result

                Dim bounds As SKRect = context.BoundsLogical
                Dim width As Single = Math.Max(1.0F, bounds.Width)

                For i As Integer = 0 To _count - 1
                    Dim top As Single = bounds.Top + CSng(i) * _rowPitch
                    Dim placementBounds As New SKRect(bounds.Left, top, bounds.Left + width, top + _rowHeight)
                    result.Add(New MASLayoutPlacement(CreateRegisteredRetainedProbeControl(i), placementBounds))
                Next

                Return result
            End Function

            Private Shared Function CreateRegisteredRetainedProbeControl(index As Integer) As MASControlBase
                ' Keep the stress proof inside the architecture contract: synthetic MASControlBase
                ' subclasses must not be introduced from audits because every concrete control type
                ' is validated against MASComponentRegistry. MASLabel is a registered, lightweight
                ' control with a parameterless/text constructor and is sufficient because the gate
                ' verifies retained placement publication/blocking, not label rendering.
                Dim control As New MASLabel(String.Empty)
                control.Name = "RetainedScrollProbe." & index.ToString(CultureInfo.InvariantCulture)
                Return control
            End Function
        End Class

        Private Shared Sub AddError(findings As IList(Of MASCompositionRuntimeStressFinding),
                                    kind As MASCompositionRuntimeStressFindingKind,
                                    code As String,
                                    message As String)
            findings.Add(New MASCompositionRuntimeStressFinding(MASCompositionRuntimeStressFindingSeverity.Error, kind, code, message))
        End Sub

        Private Shared Sub AddInfo(findings As IList(Of MASCompositionRuntimeStressFinding),
                                   kind As MASCompositionRuntimeStressFindingKind,
                                   code As String,
                                   message As String)
            findings.Add(New MASCompositionRuntimeStressFinding(MASCompositionRuntimeStressFindingSeverity.Info, kind, code, message))
        End Sub
    End Class

End Namespace
