scripts/internal/continuous-co-review/reviewer-contracts.ps1
|
$ErrorActionPreference = 'Stop' Set-StrictMode -Version Latest function Get-ContinuousCoReviewContractRoot { param( [string] $SchemaRoot, [string] $RepoRoot ) if ($SchemaRoot) { return (Resolve-Path -LiteralPath $SchemaRoot).Path } # DEPLOY-AWARE resolution. In the Specrew SOURCE repo the contracts live at # specs/197-continuous-co-review/contracts; in a DEPLOYED project (where the detached reviewer actually # runs) they are deployed to .specrew/review/contracts. Resolve relative to the project root (3 parents up # from this file = the module base, threaded as moduleBase on the detached path) and try the source layout # first, then the deployed layout. Without this the reviewer throws "schema not found" on every deployed # project (it only ever worked in-source) - the iter-007 deployed-reviewer gap. -RepoRoot overrides the # derived root (tests inject a temp root to exercise both layouts). $root = if ($RepoRoot) { (Resolve-Path -LiteralPath $RepoRoot).Path } else { (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '../../..')).Path } foreach ($rel in @('specs/197-continuous-co-review/contracts', '.specrew/review/contracts')) { $candidate = Join-Path $root $rel if (Test-Path -LiteralPath $candidate -PathType Container) { return (Resolve-Path -LiteralPath $candidate).Path } } return (Join-Path $root 'specs/197-continuous-co-review/contracts') } function Get-ReviewerContractNames { return @( 'ReviewRequest' 'FindingsResult' 'ReviewThread' 'GateVerdict' 'InfrastructureFailure' 'SpawnInvocation' ) } function Get-ReviewerContractFileName { param( [Parameter(Mandatory)] [string] $ContractName ) switch ($ContractName.ToLowerInvariant()) { 'reviewrequest' { return 'review-request.schema.json' } 'review-request' { return 'review-request.schema.json' } 'findingsresult' { return 'findings-result.schema.json' } 'findings-result' { return 'findings-result.schema.json' } 'reviewthread' { return 'review-thread.schema.json' } 'review-thread' { return 'review-thread.schema.json' } 'gateverdict' { return 'gate-verdict.schema.json' } 'gate-verdict' { return 'gate-verdict.schema.json' } 'infrastructurefailure' { return 'infrastructure-failure.schema.json' } 'infrastructure-failure' { return 'infrastructure-failure.schema.json' } 'spawninvocation' { return 'spawn-invocation.schema.json' } 'spawn-invocation' { return 'spawn-invocation.schema.json' } default { throw "Unknown reviewer contract '$ContractName'." } } } function Get-ReviewerContractSchemaPath { param( [Parameter(Mandatory)] [string] $ContractName, [string] $SchemaRoot ) $root = Get-ContinuousCoReviewContractRoot -SchemaRoot $SchemaRoot return (Join-Path $root (Get-ReviewerContractFileName -ContractName $ContractName)) } function Get-ReviewerContractSchema { param( [Parameter(Mandatory)] [string] $ContractName, [string] $SchemaRoot ) $schemaPath = Get-ReviewerContractSchemaPath -ContractName $ContractName -SchemaRoot $SchemaRoot if (-not (Test-Path -LiteralPath $schemaPath -PathType Leaf)) { throw "Reviewer contract schema not found: $schemaPath" } return (Get-Content -LiteralPath $schemaPath -Raw | ConvertFrom-Json -Depth 100) } function ConvertFrom-ReviewerContractJson { param( [Parameter(Mandatory)] [string] $Json ) try { return ($Json | ConvertFrom-Json -Depth 100) } catch { throw "Invalid reviewer contract JSON: $($_.Exception.Message)" } } function Read-ReviewerContractJson { param( [Parameter(Mandatory)] [string] $Path ) return ConvertFrom-ReviewerContractJson -Json (Get-Content -LiteralPath $Path -Raw) } function Test-ReviewerContractValueType { param( [AllowNull()] $Value, [Parameter(Mandatory)] [object] $ExpectedType ) $expectedTypes = @($ExpectedType) foreach ($expected in $expectedTypes) { switch ($expected) { 'null' { if ($null -eq $Value) { return $true } } 'string' { if (($Value -is [string]) -or ($Value -is [datetime])) { return $true } } 'integer' { if (($Value -is [byte] -or $Value -is [int16] -or $Value -is [int] -or $Value -is [long]) -and $Value -isnot [bool]) { return $true } } 'boolean' { if ($Value -is [bool]) { return $true } } 'object' { if (($null -ne $Value) -and (($Value -is [System.Collections.IDictionary]) -or ($Value -is [pscustomobject]))) { return $true } } 'array' { if (($Value -is [System.Collections.IEnumerable]) -and ($Value -isnot [string]) -and ($Value -isnot [System.Collections.IDictionary]) -and ($Value -isnot [pscustomobject])) { return $true } } default { throw "Unsupported JSON schema type '$expected'." } } } return $false } function Get-ReviewerContractPropertyNames { param( [Parameter(Mandatory)] [AllowNull()] $Object ) if ($Object -is [System.Collections.IDictionary]) { return @($Object.Keys) } return @($Object.PSObject.Properties.Name) } function Test-ReviewerContractPropertyExists { param( [Parameter(Mandatory)] [AllowNull()] $Object, [Parameter(Mandatory)] [string] $Name ) return ((Get-ReviewerContractPropertyNames -Object $Object) -contains $Name) } function Get-ReviewerContractPropertyValue { param( [Parameter(Mandatory)] [AllowNull()] $Object, [Parameter(Mandatory)] [string] $Name ) if ($Object -is [System.Collections.IDictionary]) { return $Object[$Name] } return $Object.PSObject.Properties[$Name].Value } function Test-ReviewerContractSchemaNode { param( [AllowNull()] $Value, [Parameter(Mandatory)] $Schema, [Parameter(Mandatory)] [string] $Path, [System.Collections.Generic.List[string]] $Errors ) if ($Schema.PSObject.Properties.Name -contains 'type') { if (-not (Test-ReviewerContractValueType -Value $Value -ExpectedType $Schema.type)) { $Errors.Add("$Path has the wrong JSON type.") return } } if ($Schema.PSObject.Properties.Name -contains 'const') { if ($Value -ne $Schema.const) { $Errors.Add("$Path must equal '$($Schema.const)'.") } } if ($Schema.PSObject.Properties.Name -contains 'enum') { if (@($Schema.enum) -notcontains $Value) { $Errors.Add("$Path has value '$Value' outside the allowed enum.") } } if (($null -ne $Value) -and ($Value -is [string]) -and ($Schema.PSObject.Properties.Name -contains 'minLength')) { if ($Value.Length -lt [int] $Schema.minLength) { $Errors.Add("$Path is shorter than minLength $($Schema.minLength).") } } if (($null -ne $Value) -and ($Value -isnot [string]) -and ($Schema.PSObject.Properties.Name -contains 'minimum')) { if ($Value -lt $Schema.minimum) { $Errors.Add("$Path is below minimum $($Schema.minimum).") } } if (($null -ne $Value) -and ($Value -isnot [string]) -and ($Schema.PSObject.Properties.Name -contains 'maximum')) { if ($Value -gt $Schema.maximum) { $Errors.Add("$Path is above maximum $($Schema.maximum).") } } if (($Schema.PSObject.Properties.Name -contains 'type') -and (@($Schema.type) -contains 'object') -and ($null -ne $Value)) { $schemaPropertyNames = @() if ($Schema.PSObject.Properties.Name -contains 'properties') { $schemaPropertyNames = @($Schema.properties.PSObject.Properties.Name) } if (($Schema.PSObject.Properties.Name -contains 'additionalProperties') -and ($Schema.additionalProperties -eq $false)) { foreach ($actualProperty in (Get-ReviewerContractPropertyNames -Object $Value)) { if ($schemaPropertyNames -notcontains $actualProperty) { $Errors.Add("$Path.$actualProperty is not an allowed property.") } } } if ($Schema.PSObject.Properties.Name -contains 'required') { foreach ($requiredProperty in @($Schema.required)) { if (-not (Test-ReviewerContractPropertyExists -Object $Value -Name $requiredProperty)) { $Errors.Add("$Path.$requiredProperty is required.") } } } foreach ($schemaPropertyName in $schemaPropertyNames) { if (Test-ReviewerContractPropertyExists -Object $Value -Name $schemaPropertyName) { if ($Value -is [System.Collections.IDictionary]) { $propertyValue = $Value[$schemaPropertyName] } else { $propertyValue = $Value.PSObject.Properties[$schemaPropertyName].Value } $propertySchema = $Schema.properties.PSObject.Properties[$schemaPropertyName].Value if (($propertySchema.PSObject.Properties.Name -contains 'type') -and (@($propertySchema.type) -contains 'array')) { $isJsonArray = (($propertyValue -is [System.Collections.IEnumerable]) -and ($propertyValue -isnot [string]) -and ($propertyValue -isnot [System.Collections.IDictionary]) -and ($propertyValue -isnot [pscustomobject])) if (-not $isJsonArray) { $Errors.Add("$Path.$schemaPropertyName has the wrong JSON type.") continue } Test-ReviewerContractSchemaNode -Value (, $propertyValue) -Schema $propertySchema -Path "$Path.$schemaPropertyName" -Errors $Errors } else { Test-ReviewerContractSchemaNode -Value $propertyValue -Schema $propertySchema -Path "$Path.$schemaPropertyName" -Errors $Errors } } } } if (($Schema.PSObject.Properties.Name -contains 'type') -and (@($Schema.type) -contains 'array') -and ($null -ne $Value)) { $valueItems = @($Value) if (($valueItems.Count -eq 1) -and ($valueItems[0] -is [array])) { $items = @($valueItems[0]) } else { $items = @($valueItems) } if (($Schema.PSObject.Properties.Name -contains 'minItems') -and ($items.Count -lt [int] $Schema.minItems)) { $Errors.Add("$Path has fewer items than minItems $($Schema.minItems).") } if ($Schema.PSObject.Properties.Name -contains 'items') { for ($index = 0; $index -lt $items.Count; $index++) { Test-ReviewerContractSchemaNode -Value $items[$index] -Schema $Schema.items -Path "$Path[$index]" -Errors $Errors } } } } function Test-ReviewerContractSchemaVersion { param( [Parameter(Mandatory)] [AllowNull()] $InputObject, [System.Collections.Generic.List[string]] $Errors, [string] $ContractName ) if (-not (Test-ReviewerContractPropertyExists -Object $InputObject -Name 'schema_version')) { return } $schemaVersion = if ($InputObject -is [System.Collections.IDictionary]) { $InputObject['schema_version'] } else { $InputObject.PSObject.Properties['schema_version'].Value } if ($schemaVersion -isnot [string]) { $Errors.Add('$.schema_version must be a string.') return } $major = ($schemaVersion -split '\.')[0] $allowedMajors = if ($ContractName -eq 'ReviewRequest') { @('1', '2') } else { @('1') } if ($allowedMajors -notcontains $major) { $Errors.Add("Unknown schema major version '$major'.") } } function Test-ReviewerContractObject { param( [Parameter(Mandatory)] [string] $ContractName, [Parameter(Mandatory)] [AllowNull()] $InputObject, [string] $SchemaRoot ) $errors = [System.Collections.Generic.List[string]]::new() $schema = Get-ReviewerContractSchema -ContractName $ContractName -SchemaRoot $SchemaRoot Test-ReviewerContractSchemaVersion -InputObject $InputObject -Errors $errors -ContractName $ContractName Test-ReviewerContractSchemaNode -Value $InputObject -Schema $schema -Path '$' -Errors $errors return [pscustomobject]@{ Valid = ($errors.Count -eq 0) Errors = @($errors) } } function Test-ReviewerContractJson { param( [Parameter(Mandatory)] [string] $ContractName, [Parameter(Mandatory)] [string] $Json, [string] $SchemaRoot ) try { $inputObject = ConvertFrom-ReviewerContractJson -Json $Json } catch { return [pscustomobject]@{ Valid = $false Errors = @($_.Exception.Message) } } return Test-ReviewerContractObject -ContractName $ContractName -InputObject $inputObject -SchemaRoot $SchemaRoot } function Assert-ReviewerContractObject { param( [Parameter(Mandatory)] [string] $ContractName, [Parameter(Mandatory)] [AllowNull()] $InputObject, [string] $SchemaRoot ) $result = Test-ReviewerContractObject -ContractName $ContractName -InputObject $InputObject -SchemaRoot $SchemaRoot if (-not $result.Valid) { throw "Reviewer contract '$ContractName' failed validation: $($result.Errors -join '; ')" } return $InputObject } function Get-ReviewerContractSha256Hex { param( [Parameter(Mandatory)] [string] $Text ) $bytes = [System.Text.Encoding]::UTF8.GetBytes($Text) $hashBytes = [System.Security.Cryptography.SHA256]::HashData($bytes) return ([System.BitConverter]::ToString($hashBytes) -replace '-', '').ToLowerInvariant() } function ConvertTo-ReviewerContractCanonicalJson { param( [Parameter(Mandatory)] [AllowNull()] $InputObject ) return ($InputObject | ConvertTo-Json -Depth 100 -Compress) } function ConvertTo-ReviewerContractText { param( [AllowNull()] $Value ) if ($null -eq $Value) { return $null } return ([string] $Value).Trim() } function Get-ReviewerFindingDispositionValues { return @( 'open' 'accepted_fix_pending' 'resolved' 'rejected_with_rationale' 'escalated_to_human' ) } function Get-ReviewerFindingValidDispositionValues { return Get-ReviewerFindingDispositionValues } function Test-ReviewerFindingDispositionValue { param( [Parameter(Mandatory)] [AllowEmptyString()] [string] $Disposition ) return ((Get-ReviewerFindingDispositionValues) -contains $Disposition) } function Test-ReviewerFindingDisposition { param( [Parameter(Mandatory)] [AllowEmptyString()] [string] $Disposition ) return Test-ReviewerFindingDispositionValue -Disposition $Disposition } function Get-ReviewerFindingResolutionStateValues { return @( 'unresolved' 'resolved' 'rejected' 'escalated' ) } function Get-ReviewerFindingValidResolutionStateValues { return Get-ReviewerFindingResolutionStateValues } function Test-ReviewerFindingResolutionStateValue { param( [Parameter(Mandatory)] [AllowEmptyString()] [string] $State ) return ((Get-ReviewerFindingResolutionStateValues) -contains $State) } function Test-ReviewerFindingResolutionState { param( [Parameter(Mandatory)] [AllowEmptyString()] [string] $State ) return Test-ReviewerFindingResolutionStateValue -State $State } function Get-ReviewerFindingLocationFingerprintFields { param( [AllowNull()] $Location ) $path = $null $lineStart = $null $lineEnd = $null if ($null -ne $Location) { if (Test-ReviewerContractPropertyExists -Object $Location -Name 'path') { $path = ConvertTo-ReviewerContractText -Value (Get-ReviewerContractPropertyValue -Object $Location -Name 'path') if ($null -ne $path) { $path = ($path -replace '\\', '/').ToLowerInvariant() } } if (Test-ReviewerContractPropertyExists -Object $Location -Name 'line_start') { $lineStart = Get-ReviewerContractPropertyValue -Object $Location -Name 'line_start' } if (Test-ReviewerContractPropertyExists -Object $Location -Name 'line_end') { $lineEnd = Get-ReviewerContractPropertyValue -Object $Location -Name 'line_end' } } return [ordered]@{ path = $path line_start = $lineStart line_end = $lineEnd } } function New-ReviewerFindingFingerprint { param( [AllowNull()] $Finding, [AllowNull()] $Location, [AllowNull()] [string] $Severity, [AllowNull()] [string] $Kind, [AllowNull()] [string] $DesignReference, [AllowNull()] [string] $Comment ) if ($null -ne $Finding) { if (Test-ReviewerContractPropertyExists -Object $Finding -Name 'location') { $Location = Get-ReviewerContractPropertyValue -Object $Finding -Name 'location' } if (Test-ReviewerContractPropertyExists -Object $Finding -Name 'severity') { $Severity = Get-ReviewerContractPropertyValue -Object $Finding -Name 'severity' } if (Test-ReviewerContractPropertyExists -Object $Finding -Name 'kind') { $Kind = Get-ReviewerContractPropertyValue -Object $Finding -Name 'kind' } if (Test-ReviewerContractPropertyExists -Object $Finding -Name 'design_reference') { $DesignReference = Get-ReviewerContractPropertyValue -Object $Finding -Name 'design_reference' } if (Test-ReviewerContractPropertyExists -Object $Finding -Name 'comment') { $Comment = Get-ReviewerContractPropertyValue -Object $Finding -Name 'comment' } } $fingerprintFields = [ordered]@{ location = Get-ReviewerFindingLocationFingerprintFields -Location $Location severity = ConvertTo-ReviewerContractText -Value $Severity kind = ConvertTo-ReviewerContractText -Value $Kind design_reference = ConvertTo-ReviewerContractText -Value $DesignReference comment = ConvertTo-ReviewerContractText -Value $Comment } $canonicalJson = ConvertTo-ReviewerContractCanonicalJson -InputObject $fingerprintFields return "sha256:$(Get-ReviewerContractSha256Hex -Text $canonicalJson)" } function Get-ReviewerFindingFingerprint { param( [AllowNull()] $Finding, [AllowNull()] $Location, [AllowNull()] [string] $Severity, [AllowNull()] [string] $Kind, [AllowNull()] [string] $DesignReference, [AllowNull()] [string] $Comment ) return New-ReviewerFindingFingerprint -Finding $Finding -Location $Location -Severity $Severity -Kind $Kind -DesignReference $DesignReference -Comment $Comment } function Get-ReviewerInfrastructureFailureCategoryValues { return @( 'missing-provider' 'unauthorized-provider' 'unavailable-requested-model' 'timeout' 'nonzero-exit' 'empty-stdout' 'invalid-json' 'schema-mismatch' 'command-invocation-failure' 'malformed-durable-state' 'fallback-exhausted' 'cleanup-failed' 'workspace-mutation-invalidated' # The composed reviewer prompt exceeds the host's input limit (e.g. claude -p's hard 10 MB piped # stdin), detected BEFORE invoking the host so an oversize input fails EXPLICITLY with its sizes # instead of surfacing as a contentless empty stdout. Deterministic in the input size, so NOT # retryable and NOT fallback-allowed (the diff cap / scaffolding exclusion / config override is the # fix, not a retry against the same oversized prompt). 'input-too-large' ) } function Test-ReviewerInfrastructureFailureCategory { param( [Parameter(Mandatory)] [AllowEmptyString()] [string] $Category ) return ((Get-ReviewerInfrastructureFailureCategoryValues) -contains $Category) } function Test-ReviewerInfrastructureSafeDetailName { param( [Parameter(Mandatory)] [string] $Name ) $unsafeNamePattern = '(?i)(stdout|stderr|std[_-]?out|std[_-]?err|prompt|transcript|env|environment|token|secret|password|credential|api[_-]?key|private[_-]?key|machine|hostname|computername|userprofile|home|path|pwd|cwd|working[_-]?directory)' return ($Name -notmatch $unsafeNamePattern) } function ConvertTo-ReviewerInfrastructureSafeString { param( [AllowNull()] [string] $Value ) if ($null -eq $Value) { return $null } $secretValuePatterns = @( '(?i)\bbearer\s+[a-z0-9._~+/=-]+' '(?i)\b(token|secret|password|credential|api[_-]?key)\s*[:=]\s*\S+' '\bghp_[A-Za-z0-9_]{20,}\b' '\bgithub_pat_[A-Za-z0-9_]{20,}\b' '\bsk-[A-Za-z0-9]{20,}\b' ) foreach ($pattern in $secretValuePatterns) { if ($Value -match $pattern) { return '[redacted]' } } return $Value } function ConvertTo-ReviewerInfrastructureSafeDetailValue { param( [AllowNull()] $Value ) if ($null -eq $Value) { return $null } if ($Value -is [string]) { return ConvertTo-ReviewerInfrastructureSafeString -Value $Value } if (($Value -is [bool]) -or ($Value -is [byte]) -or ($Value -is [int16]) -or ($Value -is [int]) -or ($Value -is [long]) -or ($Value -is [decimal]) -or ($Value -is [double])) { return $Value } if (($Value -is [System.Collections.IEnumerable]) -and ($Value -isnot [string]) -and ($Value -isnot [System.Collections.IDictionary]) -and ($Value -isnot [pscustomobject])) { return @($Value | ForEach-Object { ConvertTo-ReviewerInfrastructureSafeDetailValue -Value $_ }) } if (($Value -is [System.Collections.IDictionary]) -or ($Value -is [pscustomobject])) { return ConvertTo-ReviewerInfrastructureSafeDetails -SafeDetails $Value } return (ConvertTo-ReviewerInfrastructureSafeString -Value ([string] $Value)) } function ConvertTo-ReviewerInfrastructureSafeDetails { param( [AllowNull()] $SafeDetails ) $details = [ordered]@{} if ($null -eq $SafeDetails) { return [pscustomobject] $details } foreach ($propertyName in (Get-ReviewerContractPropertyNames -Object $SafeDetails)) { if (-not (Test-ReviewerInfrastructureSafeDetailName -Name $propertyName)) { continue } $details[$propertyName] = ConvertTo-ReviewerInfrastructureSafeDetailValue -Value (Get-ReviewerContractPropertyValue -Object $SafeDetails -Name $propertyName) } return [pscustomobject] $details } function Get-ReviewerInfrastructureFailureDefaultRetryable { param( [Parameter(Mandatory)] [string] $Category ) return (@( 'missing-provider' 'timeout' 'nonzero-exit' 'empty-stdout' 'invalid-json' 'command-invocation-failure' ) -contains $Category) } function Get-ReviewerInfrastructureFailureDefaultFallbackAllowed { param( [Parameter(Mandatory)] [string] $Category ) return (@( 'missing-provider' 'timeout' 'nonzero-exit' 'empty-stdout' 'invalid-json' 'command-invocation-failure' 'unavailable-requested-model' ) -contains $Category) } function New-ReviewerInfrastructureFailureId { param( [Parameter(Mandatory)] [string] $RunId, [AllowNull()] [string] $InvocationId, [Parameter(Mandatory)] [string] $Category, [Parameter(Mandatory)] [string] $Message ) $idFields = [ordered]@{ run_id = $RunId invocation_id = $InvocationId category = $Category message = $Message } $hash = Get-ReviewerContractSha256Hex -Text (ConvertTo-ReviewerContractCanonicalJson -InputObject $idFields) return "failure-$($hash.Substring(0, 16))" } function New-ReviewerInfrastructureFailure { param( [Parameter(Mandatory)] [string] $RunId, [Parameter(Mandatory)] [string] $Category, [Parameter(Mandatory)] [string] $Message, [AllowNull()] [string] $InvocationId, [AllowNull()] [string] $FailureId, [AllowNull()] $SafeDetails, [AllowNull()] [System.Nullable[bool]] $Retryable, [AllowNull()] [System.Nullable[bool]] $FallbackAllowed, [datetime] $CreatedAt = [datetime]::MinValue ) if (-not (Test-ReviewerInfrastructureFailureCategory -Category $Category)) { throw "Unknown infrastructure failure category '$Category'." } $safeMessage = ConvertTo-ReviewerInfrastructureSafeString -Value $Message $resolvedInvocationId = if ([string]::IsNullOrWhiteSpace($InvocationId)) { $null } else { $InvocationId } $resolvedCreatedAt = if ($CreatedAt -eq [datetime]::MinValue) { [datetime]::UtcNow } else { $CreatedAt.ToUniversalTime() } $resolvedRetryable = if ($PSBoundParameters.ContainsKey('Retryable')) { [bool] $Retryable } else { Get-ReviewerInfrastructureFailureDefaultRetryable -Category $Category } $resolvedFallbackAllowed = if ($PSBoundParameters.ContainsKey('FallbackAllowed')) { [bool] $FallbackAllowed } else { Get-ReviewerInfrastructureFailureDefaultFallbackAllowed -Category $Category } $resolvedFailureId = if ([string]::IsNullOrWhiteSpace($FailureId)) { New-ReviewerInfrastructureFailureId -RunId $RunId -InvocationId $resolvedInvocationId -Category $Category -Message $safeMessage } else { $FailureId } $failure = [ordered]@{ schema_version = '1.0' failure_id = $resolvedFailureId run_id = $RunId invocation_id = $resolvedInvocationId category = $Category message = $safeMessage safe_details = ConvertTo-ReviewerInfrastructureSafeDetails -SafeDetails $SafeDetails retryable = $resolvedRetryable fallback_allowed = $resolvedFallbackAllowed created_at = $resolvedCreatedAt.ToString('yyyy-MM-ddTHH:mm:ssZ', [System.Globalization.CultureInfo]::InvariantCulture) } return [pscustomobject] $failure } function New-ReviewerContractInfrastructureFailure { param( [Parameter(Mandatory)] [string] $RunId, [Parameter(Mandatory)] [string] $Category, [Parameter(Mandatory)] [string] $Message, [AllowNull()] [string] $InvocationId, [AllowNull()] [string] $FailureId, [AllowNull()] $SafeDetails, [AllowNull()] [System.Nullable[bool]] $Retryable, [AllowNull()] [System.Nullable[bool]] $FallbackAllowed, [datetime] $CreatedAt = [datetime]::MinValue ) $parameters = @{ RunId = $RunId Category = $Category Message = $Message } foreach ($optionalName in @('InvocationId', 'FailureId', 'SafeDetails', 'Retryable', 'FallbackAllowed', 'CreatedAt')) { if ($PSBoundParameters.ContainsKey($optionalName)) { $parameters[$optionalName] = $PSBoundParameters[$optionalName] } } return New-ReviewerInfrastructureFailure @parameters } function Get-ContinuousCoReviewFindingDispositionValues { return Get-ReviewerFindingDispositionValues } function Get-ContinuousCoReviewFindingResolutionStates { return Get-ReviewerFindingResolutionStateValues } function New-ContinuousCoReviewFindingFingerprint { param( [AllowNull()] $Finding, [AllowNull()] $Location, [AllowNull()] [string] $Severity, [AllowNull()] [string] $Kind, [AllowNull()] [string] $DesignReference, [AllowNull()] [string] $Comment ) return New-ReviewerFindingFingerprint -Finding $Finding -Location $Location -Severity $Severity -Kind $Kind -DesignReference $DesignReference -Comment $Comment } function New-ContinuousCoReviewInfrastructureFailure { param( [Parameter(Mandatory)] [string] $RunId, [Parameter(Mandatory)] [string] $Category, [Parameter(Mandatory)] [string] $Message, [AllowNull()] [string] $InvocationId, [AllowNull()] [string] $FailureId, [AllowNull()] $SafeDetails, [AllowNull()] [System.Nullable[bool]] $Retryable, [AllowNull()] [System.Nullable[bool]] $FallbackAllowed, [datetime] $CreatedAt = [datetime]::MinValue ) $parameters = @{ RunId = $RunId Category = $Category Message = $Message } foreach ($optionalName in @('InvocationId', 'FailureId', 'SafeDetails', 'Retryable', 'FallbackAllowed', 'CreatedAt')) { if ($PSBoundParameters.ContainsKey($optionalName)) { $parameters[$optionalName] = $PSBoundParameters[$optionalName] } } return New-ReviewerInfrastructureFailure @parameters } |